Swift - 表格section header增加滑动删除功能(删除该分区下所有cell)
我们知道 UITableView 的单元格自带滑动删除功能,设置后只要在单元格 cell 上向左滑动,右侧就会自动出现删除按钮,如下图:

但这样一次只能删除一条记录,不能批量删除。我们可以通过自定义表格的分组头(section header),在其上面增加滑动删除功能,这样滑动分组头时就可以删除该 section 下所有的单元格。
1,效果图
- 在分区头部(section header)上向左滑动,右侧会出现一个“全部删除”按钮。向右滑动又会隐藏删除按钮。这两个过程都是有动画效果的。
- 点击“全部删除”按钮,可以将其所在的整个分区数据删除。
注意:建议使用真机进行调试,模拟器运行时会出现只有一个分区头可以滑动删除的问题。


2,样例代码
(1)SwipeableSectionHeader.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 | import UIKit //自定义滑动分区头代理协议 protocol SwipeableSectionHeaderDelegate { //删除分区 func deleteSection(section: Int ) } //自定义滑动分区头 class SwipeableSectionHeader : UIView { //分区索引 var section: Int = 0 //放置文本标签和按钮的容器 var container: UIView ! //标题文本标签 var titleLabel: UILabel ! //删除按钮 var deleteButton: UIButton ! //代理对象 var delegate: SwipeableSectionHeaderDelegate ? //向左滑动手势 var swipeLeft: UISwipeGestureRecognizer ! //向右滑动手势 var swipeRight: UISwipeGestureRecognizer ! override init (frame: CGRect ) { super . init (frame: frame) //背景为黑色 self .backgroundColor = UIColor .black //初始化容器 self .container = UIView () self .addSubview(container) //初始标题文本标签 self .titleLabel = UILabel () self .titleLabel.textColor = UIColor .white self .titleLabel.textAlignment = .center self .container.addSubview( self .titleLabel) //初始化删除按钮 self .deleteButton = UIButton (type: .custom) self .deleteButton.backgroundColor = UIColor (red: 0xfc/255, green: 0x21/255, blue: 0x25/255, alpha: 1) self .deleteButton.setTitle( "删除全部" , for :.normal) self .deleteButton.titleLabel?.font = UIFont .systemFont(ofSize: 15) self .deleteButton.addTarget( self , action:#selector(buttonTapped(_:)), for :.touchUpInside) self .container.addSubview( self .deleteButton) //向左滑动手势 self .swipeLeft = UISwipeGestureRecognizer (target: self , action:#selector(headerViewSwiped(_:))) self .swipeLeft.direction = .left self .addGestureRecognizer( self .swipeLeft) //向右滑动手势 self .swipeRight = UISwipeGestureRecognizer (target: self , action:#selector(headerViewSwiped(_:))) self .swipeRight.direction = .right self .addGestureRecognizer( self .swipeRight) } required init ?(coder aDecoder: NSCoder ) { fatalError( "init(coder:) has not been implemented" ) } //滑动响应 @objc func headerViewSwiped(_ recognizer: UISwipeGestureRecognizer ){ if recognizer.state == .ended { var newFrame = self .container.frame //向左滑动显示出删除按钮,向右滑动隐藏删除按钮 if recognizer.direction == .left { newFrame.origin.x = - self .deleteButton.frame.width } else { newFrame.origin.x = 0 } //播放动画 UIView .animate(withDuration: 0.25, animations: { ()-> Void in self .container.frame = newFrame }) } } //删除按钮点击 @objc func buttonTapped(_ button: UIButton ){ delegate?.deleteSection(section: section) } //子视图布局 override func layoutSubviews() { super .layoutSubviews() self .container.frame = CGRect (x: 0, y:0, width: self .frame.width + 74, height: self .frame.height) self .titleLabel.frame = CGRect (x: 0, y:0, width: self .frame.width, height: self .frame.height) self .deleteButton.frame = CGRect (x: self .frame.size.width, y:0, width:74, height: self .frame.height) } } |
(2)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 | import UIKit class ViewController : UIViewController , UITableViewDelegate , UITableViewDataSource , UIGestureRecognizerDelegate , SwipeableSectionHeaderDelegate { var tableView: UITableView ! var adHeaders:[ String ]! var allnames:[[ String ]]! override func loadView() { super .loadView() } override func viewDidLoad() { super .viewDidLoad() //初始化数据,这一次数据,我们放在属性列表文件里 self .allnames = [[ "UILabel 标签" , "UIButton 按钮" ], [ "UIDatePiker 日期选择器" , "UITableView 表格视图" ], [ "UICollectionView 网格" ] ] self .adHeaders = [ "常见 UIKit 控件" , "中级 UIKit 控件" , "高级 UIKit 控件" ] //创建表视图 self .tableView = UITableView (frame: self .view.frame, style:.grouped) self .tableView.delegate = self self .tableView.dataSource = self //创建一个重用的单元格 self .tableView.register( UITableViewCell . self , forCellReuseIdentifier: "SwiftCell" ) self .view.addSubview( self .tableView) } //在本例中,有3个分区 func numberOfSections( in tableView: UITableView ) -> Int { return self .adHeaders.count } //返回表格行数(也就是返回控件数) func tableView(_ tableView: UITableView , numberOfRowsInSection section: Int ) -> Int { let data = self .allnames[section] return data.count } //返回自定义的分区头 func tableView(_ tableView: UITableView , viewForHeaderInSection section: Int ) -> UIView ? { let headerView = SwipeableSectionHeader () //设置代理 headerView.delegate = self //设置标题 headerView.titleLabel.text = self .adHeaders[section] //设置分区索引 headerView.section = section //设置手势优先级(否则将与表格自带的手势冲突,造成滑动分区头时出现第一个cell的删除按钮) if let gestureRecognizers = tableView.gestureRecognizers { for recognizer in gestureRecognizers { recognizer.require(toFail: headerView.swipeLeft) } } return headerView } //返回分区头部高度 func tableView(_ tableView: UITableView , heightForHeaderInSection section: Int ) -> CGFloat { return 40 } // UITableViewDataSource协议中的方法,该方法的返回值决定指定分区的尾部 func tableView(_ tableView: UITableView , titleForFooterInSection section: Int ) -> String ? { let data = self .allnames[section] return "有\(data.count)个控件" } //创建各单元显示内容(创建参数indexPath指定的单元) func tableView(_ tableView: UITableView , cellForRowAt indexPath: IndexPath ) -> UITableViewCell { //为了提供表格显示性能,已创建完成的单元需重复使用 let identify: String = "SwiftCell" //同一形式的单元格重复使用,在声明时已注册 let cell = tableView.dequeueReusableCell(withIdentifier: identify, for : indexPath) cell.accessoryType = .disclosureIndicator let secno = indexPath.section var data = self .allnames[secno] cell.textLabel?.text = data[indexPath.row] return cell } //删除整个分区 func deleteSection(section: Int ) { self .adHeaders.remove(at: section) self .allnames.remove(at: section) self .tableView.reloadData() } //设置单元格的编辑的样式 func tableView(_ tableView: UITableView , editingStyleForRowAt indexPath: IndexPath ) -> UITableViewCellEditingStyle { return UITableViewCellEditingStyle .delete } //设置确认删除按钮的文字 func tableView(_ tableView: UITableView , titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath ) -> String ? { return "删除" } //单元格编辑后(删除或插入)的响应方法 func tableView(_ tableView: UITableView , commit editingStyle: UITableViewCellEditingStyle , forRowAt indexPath: IndexPath ) { self .allnames[indexPath.section].remove(at: indexPath.row) self .tableView.reloadData() print ( "你确认了删除按钮" ) } override func didReceiveMemoryWarning() { super .didReceiveMemoryWarning() } } |
你这个 会存在复用问题吧
真机调试也是一样的情况,代码对比过好几次了都是跟你一样的,不知道问题出在哪
为什么第一个分区头可以左滑,其他的分区头都不行