返回 导航

Swift

hangge.com

Swift - 表格section header增加滑动删除功能(删除该分区下所有cell)

作者:hangge | 2017-10-25 08:10
我们知道 UITableView 的单元格自带滑动删除功能,设置后只要在单元格 cell 上向左滑动,右侧就会自动出现删除按钮,如下图:

但这样一次只能删除一条记录,不能批量删除。我们可以通过自定义表格的分组头(section header),在其上面增加滑动删除功能,这样滑动分组头时就可以删除该 section 下所有的单元格。

1,效果图

  • 在分区头部(section header)上向左滑动,右侧会出现一个“全部删除”按钮。向右滑动又会隐藏删除按钮。这两个过程都是有动画效果的。
  • 点击“全部删除”按钮,可以将其所在的整个分区数据删除。
注意:建议使用真机进行调试,模拟器运行时会出现只有一个分区头可以滑动删除的问题。
         

2,样例代码

(1)SwipeableSectionHeader.swift(自定义的滑动分区头)
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(使用样例)
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()
    }
}
评论

全部评论(3)

回到顶部