(本文代码已升级至Swift3)
 

本文演示如何制作一个可以编辑单元格内容的表格(UITableView)。

1,效果图
(1)默认状态下,表格不可编辑,当点击单元格的时候会弹出提示框显示选中的内容。
                 
(2)点击导航栏右侧编辑按钮,表格进入可以编辑状态
(3)这时我们可以删除表格项。
(4)也可以拖动调整单元格的顺序。
(5)然后就是本文的重点,在编辑状态下。直接点击单元格,即可在当前页面下直接编辑修改单元格中的内容。
2,单元格编辑功能讲解
(1)通过自定义 UITableViewCell,在其内部添加一个 textField 来实现可编辑的cell。
(2)通过改变 userInteractionEnabled 属性,可以让 textField 在可编辑与只读两个状态间切换。
(3)在编辑状态下要加大 textField 的左边距,因为左侧会出现个删除按钮图标。

(4)同时在编辑 cell 内容的时候,由于键盘会弹出挡到后面的表格。所以我们在键盘出现的时候,要通过改变 edgeInsets 的办法在底部加大 tableview 的 contentview 大小。

而结束编辑隐藏键盘时,需要还原 tableview 的 contentview 的尺寸。
3,程序代码
--- MyTableViewCell.swift(自定义单元格类)---
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import UIKit
 
//表格数据实体类
class ListItem: NSObject {
    var text: String
     
    init(text: String) {
        self.text = text
    }
}
 
//单元格类
class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
    //单元格内部标签(可输入)
    let label:UITextField
    //单元格左边距
    var leftMarginForLabel: CGFloat = 15.0
     
    //单元格数据
    var listItem:ListItem? {
        didSet {
            label.text = listItem!.text
        }
    }
     
    //单元格是否可编辑
    var labelEditable:Bool? {
        didSet {
            label.isUserInteractionEnabled = labelEditable!
            //如果是可以编辑的话,要加大左边距(因为左边有个删除按钮)
            leftMarginForLabel = labelEditable! ? 45.0 : 15.0
            self.setNeedsLayout()
        }
    }
     
    //初始化
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        //初始化文本标签
        label = UITextField(frame: CGRect.null)
        label.textColor = UIColor.black
        label.font = UIFont.systemFont(ofSize: 16)
         
        super.init(style: style, reuseIdentifier: reuseIdentifier)
         
        //设置文本标签代理
        label.delegate = self
        label.contentVerticalAlignment = UIControlContentVerticalAlignment.center
        //添加文本标签
        addSubview(label)
    }
     
    //布局
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = CGRect(x: leftMarginForLabel, y: 0,
                             width: bounds.size.width - leftMarginForLabel,
                             height: bounds.size.height)
    }
     
    //键盘回车
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return false
    }
     
    //结束编辑
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        if listItem != nil {
            listItem?.text = textField.text!
        }
        return true
    }
     
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
--- ViewController.swift(主类)---
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import UIKit
 
class ViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource{
     
    //表格
    var tableView:UITableView?
    //表格数据
    var listItems = [ListItem]()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //初始化数据
        listItems = [ListItem(text: "这是条目1"), ListItem(text: "这是条目2"),
                     ListItem(text: "这是条目3"), ListItem(text: "这是条目4"),
                     ListItem(text: "这是条目5"), ListItem(text: "这是条目6"),
                     ListItem(text: "这是条目7"), ListItem(text: "这是条目8"),
                     ListItem(text: "这是条目9"), ListItem(text: "这是条目10"),
                     ListItem(text: "这是条目11"), ListItem(text: "这是条目12"),
                     ListItem(text: "这是条目13"), ListItem(text: "这是条目14"),
                     ListItem(text: "这是条目15"), ListItem(text: "这是条目16"),
                     ListItem(text: "这是条目17")]
         
        //创建表视图
        self.tableView = UITableView(frame:self.view.frame, style:.plain)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //创建一个重用的单元格
        self.tableView!.register(MyTableViewCell.self, forCellReuseIdentifier: "tableCell")
        self.view.addSubview(self.tableView!)
         
        //监听键盘弹出通知
        NotificationCenter.default
            .addObserver(self,selector: #selector(keyboardWillShow(_:)),
                         name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        //监听键盘隐藏通知
        NotificationCenter.default
            .addObserver(self,selector: #selector(keyboardWillHide(_:)),
                         name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
     
    //导航栏编辑按钮点击
    @IBAction func editBarBtnClick(_ sender: UIBarButtonItem) {
        //在正常状态和编辑状态之间切换
        if(self.tableView!.isEditing == false){
            self.tableView!.setEditing(true, animated:true)
            sender.title = "保存"
        }
        else{
            self.tableView!.setEditing(false, animated:true)
            sender.title = "编辑"
        }
        //重新加载表数据(改变单元格输入框编辑/只读状态)
        self.tableView?.reloadData()
    }
     
    //在本例中,有1个分区
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
     
    //返回表格行数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listItems.count
    }
     
    //创建各单元显示内容(创建参数indexPath指定的单元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell
    {
        let cell = tableView
            .dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
            as! MyTableViewCell
        //设置单元格内容
        let item = listItems[(indexPath as NSIndexPath).row]
        cell.listItem = item
        cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
        //内容标签是否可编辑
        cell.labelEditable = tableView.isEditing
        return cell
    }
     
    // UITableViewDelegate 方法,处理列表项的选中事件
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        self.tableView!.deselectRow(at: indexPath, animated: true)
        let itemString = listItems[(indexPath as NSIndexPath).row].text
        let alertController = UIAlertController(title: "提示!",
                                                message: "你选中了【\(itemString)】",
            preferredStyle: .alert)
        let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: nil)
    }
     
    //是否有删除功能
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath)
        -> UITableViewCellEditingStyle
    {
        if(self.tableView!.isEditing == false){
            return UITableViewCellEditingStyle.none
        }else{
            return UITableViewCellEditingStyle.delete
        }
    }
     
    //删除提示
    func tableView(_ tableView: UITableView,
                   titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath)
        -> String? {
            return "确定删除?"
    }
     
    //编辑完毕(这里只有删除操作)
    func tableView(_ tableView: UITableView,
                   commit editingStyle: UITableViewCellEditingStyle,
                   forRowAt indexPath: IndexPath) {
        if(editingStyle == UITableViewCellEditingStyle.delete)
        {
            self.listItems.remove(at: (indexPath as NSIndexPath).row)
            self.tableView!.reloadData()
            print("你确认了删除按钮")
        }
    }
     
    //在编辑状态,可以拖动设置cell位置
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }
     
    //移动cell事件
    func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath,
                   to toIndexPath: IndexPath) {
        if fromIndexPath != toIndexPath{
            //获取移动行对应的值
            let itemValue:ListItem = listItems[(fromIndexPath as NSIndexPath).row]
            //删除移动的值
            listItems.remove(at: (fromIndexPath as NSIndexPath).row)
            //如果移动区域大于现有行数,直接在最后添加移动的值
            if (toIndexPath as NSIndexPath).row > listItems.count{
                listItems.append(itemValue)
            }else{
                //没有超过最大行数,则在目标位置添加刚才删除的值
                listItems.insert(itemValue, at:(toIndexPath as NSIndexPath).row)
            }
        }
    }
     
    // 键盘显示
    func keyboardWillShow(_ notification: Notification) {
        let userInfo = (notification as NSNotification).userInfo!
        //键盘尺寸
        let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey]
            as! NSValue).cgRectValue
        var contentInsets:UIEdgeInsets
        //判断是横屏还是竖屏
        let statusBarOrientation = UIApplication.shared.statusBarOrientation
        if UIInterfaceOrientationIsPortrait(statusBarOrientation) {
            contentInsets = UIEdgeInsetsMake(64.0, 0.0, (keyboardSize.height), 0.0);
        } else {
            contentInsets = UIEdgeInsetsMake(64.0, 0.0, (keyboardSize.width), 0.0);
        }
        //tableview的contentview的底部大小
        self.tableView!.contentInset = contentInsets;
        self.tableView!.scrollIndicatorInsets = contentInsets;
    }
     
    // 键盘隐藏
    func keyboardWillHide(_ notification: Notification) {
        //还原tableview的contentview大小
        let contentInsets:UIEdgeInsets = UIEdgeInsetsMake(64.0, 0.0, 0, 0.0);
        self.tableView!.contentInset = contentInsets
        self.tableView!.scrollIndicatorInsets = contentInsets
    }
     
    //页面移除时
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidAppear(animated)
        //取消键盘监听通知
        NotificationCenter.default.removeObserver(self)
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

源码下载:hangge_1175.zip
原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1175.html

Swift - 可编辑表格样例(可直接编辑单元格中内容、移动删除单元格)的更多相关文章

  1. Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)

    1,反射(Reflection) 对于C#.Java开发人员来说,肯定都对反射这个概念相当熟悉.所谓反射就是可以动态获取类型.成员信息,同时在运行时(而非编译时)可以动态调用任意方法.属性等行为的特性 ...

  2. WEB打印控件Lodop(V6.x)使用说明及样例

    WEB打印控件Lodop(V6.x)使用说明及样例 Lodop是专业WEB控件,用它既可裁剪输出页面内容,又可用程序代码生成复杂打印页. 控件功能强大,却简单易用,所有调用如同JavaScript扩展 ...

  3. Java 8 时间日期库的20个使用演示样例

    除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务演示样例来学习怎样使用Java 8的这套API.Java对日 ...

  4. odoo开发笔记--form视图按钮样例

    如图: 对应后台views视图,class可选内容值: class="oe_highlight" class="btn-xs" class="btn- ...

  5. ABBYY FineReader 15 新增编辑表格单元格功能

    ABBYY FineReader 15(Windows系统)新增编辑表格单元格功能,在PDF文档存在表格的前提下,可将表中的每个单元格作为单独的文字块进行单独编辑,单元格内的编辑不会影响同一行中其他单 ...

  6. 大数据学习day16------第三阶段-----scala04--------1. 模式匹配和样例类 2 Akka通信框架

    1. 模式匹配和样例类 Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句.类型检查等.并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配 1.1 模式匹 ...

  7. 【Demo】jQuery 可编辑表格

    功能实现: (1)设定单元格的单击事件,判定被单击单元格是否已经是可编辑状态: (2)取出单元格原有内容,想单元格中加入文本框,并把原有内容显示在文本框中: (3)当用户编辑完成或者取消编辑后,将文本 ...

  8. 获取wpf datagrid当前被编辑单元格的内容

    原文 获取wpf datagrid当前被编辑单元格的内容 确认修改单元个的值, 使用到datagrid的两个事件 开始编辑事件 BeginningEdit="dataGrid_Beginni ...

  9. SNF快速开发平台MVC-各种级联绑定方式,演示样例程序(包含表单和表格控件)

    做了这么多项目,经常会使用到级联.联动的情况. 如:省.市.县.区.一级分类.二级分类.三级分类.仓库.货位. 方式:有表单需要做级联的,还是表格行上需要做级联操作的. 实现:实现方法也有很多种方式. ...

随机推荐

  1. 前端编码规范(2)HTML 规范

    文档类型 推荐使用 HTML5 的文档类型申明: <!DOCTYPE html> (建议使用 text/html 格式的 HTML.避免使用 XHTML.XHTML 以及它的属性,比如 a ...

  2. Eclipse安装配置——For Java

    1.下载安装JRE 2.下载Eclipse,解压到相应文件夹 3.配置Eclipse 3.1 配置字体大小  -12号 3.2配置workspace默认编码,utf-8,默认系统windows 3.3 ...

  3. SqlServer 导出指定表数据 生成Insert脚本

    版权声明:本文为博主原创文章,未经博主允许不得转载.

  4. JAVA;使用java.awt.Image的不稳定性

    在使用awt的image时候,不是能时时获取到图像的宽和高, GetWidth()函数偶尔得到的值为-1,暂时没有找到解决方法. 代码: public class picture extends JF ...

  5. OpenCV中的模板匹配/Filter2d

    1.模板匹配 模板匹配是在图像中寻找目标的方法之一.Come On, Boy.我们一起来看看模板匹配到底是怎么回事. 参考链接:http://www.opencv.org.cn/opencvdoc/2 ...

  6. 肯德基收银系统java

    参考肯德基官网的信息模拟肯德基快餐店的收银系统,合理使用C++或Java或Python结合设计模式(2种以上)至少实现系统的以下功能: 1.正常餐品结算和找零. 2.基本套餐结算和找零. 3.使用优惠 ...

  7. eas之kdtable分组

    如何指定是否要进行数据分组以及对哪些列进行分组 // 指定KDTable要进行数据分组 table.getGroupManager().setGroup(true); // 指明要对0.1.2三列进行 ...

  8. 还不打算去认识一下webpack?

    前言 随我来,去看看webpack!(为时未晚)============>第一版(较浅显的知识,懂得可忽略本文) 方向 安装,起步搭建运行. (粗略代过) 对于资源的管理,对于输出的管理. (举 ...

  9. python项目开发:学员管理系统

    学员管理系统 #需求: 1.用户角色:讲师/学员,登陆后根据角色不同能做的事情不同 2.讲师视图 - 管理班级,可创建班级,根据学员qq号把学员加入班级 - 可创建指定班级的上课纪录,注意一节上课纪录 ...

  10. 渗透实战(周四):CSRF跨站域请求伪造

    上图是广东外语外贸大学北校区内MBA中心旁边酒店房间的Wi-Fi网络环境,假设我们的Kali攻击机连入到SSID为414(房间号)的Wi-Fi网络,其IP地址:192.168.43.80 .同一Wi- ...