Swift - 可编辑表格样例(可直接编辑单元格中内容、移动删除单元格)

(本文代码已升级至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

时间: 2024-08-13 18:36:18

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

python xlrd xlwt获取数据到execl表格样例

import mock #coding:gbkfrom xlrd import open_workbookimport mockimport xlrdimport xlwtfrom xlutils.copy import copyimport osacct = mock.acct_iddata = mock.acct_datastart_time = mock.start_timeprint start_timeend_time = mock.end_time5haoshi = mock.res

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

1,反射(Reflection) 对于C#.Java开发人员来说,肯定都对反射这个概念相当熟悉.所谓反射就是可以动态获取类型.成员信息,同时在运行时(而非编译时)可以动态调用任意方法.属性等行为的特性. 以Java上的两个知名框架(hibernate和spring)为例.hibernate的属性映射就是通过反射来赋值的,spring的bean的创建就是根据配置的class来反射构建的. 2,Objective-C 的 Runtime在使用ObjC开发时很少强调其反射概念,因为ObjC的Runti

将 Android* x86 NDK 用于 Eclipse* 并移植 NDK 演示样例应用

目标 面向 Eclipse (ADT) 的 Android 插件如今支持基于 NDK 的应用开发. 其可自己主动生成项目和构件文件以及代码存根,并可集成到整个 Android 应用开发中(构建原生库.将库拷贝到项目内的对应 JNI 目录.将应用打包以及生成带有 NDK 代码的终于 APK). 本文将讨论怎样配置 Eclipse 以利用该功能.并示范移植 NDK 应用的演示样例. 配置 Eclipse ADT 插件以配合 NDK 使用 必须先配置 Eclipse ADT 插件指向 NDK 安装路径

<<锋利的jQuery>>样例改进利用, html文本输入框得到与失去输入焦点的提示信息显示切换函数

该书第二版3.2.10一节中,介绍val()方法时,所用的样例代码是有共性的,而且该样例的场景模式在实际工作中会用到,所以试着优化了一下,写了一个html文本输入框得到与失去输入焦点的提示信息显示切换函数.原书代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

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

除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务演示样例来学习怎样使用Java 8的这套API.Java对日期,日历及时间的处理一直以来都饱受诟病.尤其是它决定将java.util.Date定义为可改动的以及将SimpleDateFormat实现成非线程安全的. 看来Java已经意识到须要为时间及日期功能提供更好的支持了,这对已经习惯使用Joda时间日期库的社区而言也是件好事. 关于这个新的时间日期库的最

ADF Faces 表格应用基础案例二:动态字段+事件处理【附样例工程】

本文提供一个基于ADF Face组件开发样例工程,实现表格开发中常见的处理: 1.Map对象+Bean对象填充表格的数据行. 2.使用静态列.动态列.嵌套列的实现方法. 3.介绍表格中表单组件的使用方法. 4.介绍表格单行选中事件的处理过程. 本文是基于"ADF Faces 表格应用基础案例一:应用List<Class>填充文本表格"编写的,会省去许多细节部分的介绍. 实现的基本思路: 将样例工程的创建过程分为几个小的阶段,每个阶段实现了不同的目标. 第一阶段: 表格数据:

Swift - 使用socket进行通信(附聊天室样例)

在Swift开发中,如果我们需要保持客服端和服务器的长连接进行双向的数据通信,使用socket是一种很好的解决方案. 下面通过一个聊天室的样例来演示socket通信,这里我们使用了一个封装好的socket库(SwiftSocket). 功能如下: 1,程序包含服务端和客服端,这里为便于调试把服务端和客服端都做到一个应用中 2,程序启动时,自动初始化启动服务端,并在后台开启一个线程等待客服端连接 3,同时,客户端初始化完毕后会与服务端进行连接,同时也在后台开启一个线程等待接收服务端发送的消息 4,

Swift - 动画效果的实现方法总结(附样例)

在iOS中,实现动画有两种方法.一个是统一的animateWithDuration,另一个是组合出现的beginAnimations和commitAnimations.这三个方法都是类方法. 一,使用animateWithDuration来实现动画 (1)此方法共有5个参数: duration:动画从开始到结束的持续时间,单位是秒 delay:动画开始前等待的时间 options:动画执行的选项.里面可以设置动画的效果.可以使用UIViewAnimationOptions类提供的各种预置效果 a

Swift - 自动布局库SnapKit的使用详解1(配置、使用方法、样例)

为了适应各种屏幕尺寸,iOS 6后引入了自动布局(Auto Layout)的概念,通过使用各种 Constraint(约束)来实现页面自适应弹性布局. 在 StoryBoard 中使用约束实现自动布局很方便,但如果用纯代码来设置约束就很麻烦了.这里向大家推荐一个好用的第三方布局库:SnapKit(其前身是 Masonry,一个OC版的布局库) 1.SnapKit介绍 SnapKit是一个优秀的第三方自适应布局库,它可以让iOS.OS X应用更简单地实现自动布局(Auto Layout).GtiH