UITableView--点击选择与展开

本文是一个实例讲解
很多App都会有一页让用户选择喜好,会涉及喜好分类以及选择
本文将讲解大致的实现过程

每一个Cell前面会有一个Checkbox,通过Checkbox来表示是否选择
每个分类的Section可以收起或展开


最终效果


实现一个带Checkbox的Cell

iOS的基础控件中并没有Checkbox这个组件,我们可以用UIButton来代替,因为UIButton都有状态属性,可以满足我们的要求
Cell的构造很简单,只需要一个UILable与一个UIButton
因为用户是点击整个Cell可以进行选择,所以应该禁止UIButton的交互,否则会有拦截点击事件的问题

private let topicLabel: UILabel = {
        let label = UILabel()
        return label
    }()

private let checkBoxButton: UIButton = {
        let button = UIButton()
        button.setImage(UIImage(named: "lightCheckboxOff"), for: .normal)
        button.setImage(UIImage(named: "lightCheckboxOn"), for: .selected)
        button.isUserInteractionEnabled = false
        return button
    }()

与其说点击改变UIButton的状态,倒不如说是改变Cell的状态,只不过UIButton将改变的结果展示出来,我们需要开放一个是否选择的属性给外层调用,在点击Cell的时候改变checkBoxButton的状态

public var isChecked: Bool = false {
        didSet {
            checkBoxButton.isSelected = isChecked
        }
    }

在UITableViewDelegate的didSelectRowAt方法里面进行选择的操作,点击Cell的时候获取对应indexPath的数据,是否展开的值取反,然后设置Cell的isChecked属性改变checkBoxButton与文字颜色,最后刷新

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = TableViewCell_checkbox()
        let model = models[indexPath.section]
        let row = model.rows[indexPath.row]
        row.isChecked = !row.isChecked
        cell.isChecked = row.isChecked
        tableView.performBatchUpdates({
            tableView.reloadRows(at: [indexPath], with: .automatic)
        }, completion: nil)
    }

到此为止,一个带checkBox可以点击选择的Cell已经完成了
下面我们来做点击header收起展开的功能

实现一个Header

这里的header只有一个ULabel与一个箭头,section展开与收起箭头会改变方向

private lazy var sectionLabel: UILabel = {
        let label = UILabel()
        return label
    }()

    private lazy var arrowIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "iconRightArrowGrey")
        imageView.contentMode = .scaleAspectFit
        imageView.transform = CGAffineTransform(rotationAngle: .pi / 2)
        return imageView
    }()

同样的,header需要有一个是否展开的属性开控制箭头的方向

public var isExpand: Bool = true {
        didSet {
            arrowIcon.transform = isExpand ? CGAffineTransform(rotationAngle: 3 * .pi / 2) : CGAffineTransform(rotationAngle: .pi / 2)
        }
    }

header是一个UIView,我们在整个View上添加一个手势,然后调用代理方法,让外层的ViewController实现代理方法

// 定义协议
protocol ExpandHeaderDelegate: class {
    func didTapSection(header: ExpandHeader, section: Int)
}

@objc func tapHeader(gestureRecognizer: UITapGestureRecognizer) {
        guard let header = gestureRecognizer.view as? ExpandHeader else {
            return
        }
        delegate?.didTapSection(header: self, section: header.section)
    }

设置header

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        guard let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ExpandHeader") as? ExpandHeader else { return nil }
        let model = models[section]
        header.setHeaderTitle(model.section)
        header.section = section
        header.delegate = self
        header.isExpand = model.expand
        return header
    }

代理方法实现思路与Cell点击类似,就是获取数据改变状态然后刷新

func didTapSection(header: ExpandHeader, section: Int) {
        models[section].expand = !models[section].expand
        tableView.reloadSections([section], with: .automatic)
    }

这里是整个项目的Demo
支持原创,版权所有

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 13,902评论 1 32
  • HTML 5 HTML5概述 因特网上的信息是以网页的形式展示给用户的,因此网页是网络信息传递的载体。网页文件是用...
    阿啊阿吖丁阅读 10,099评论 0 0
  • 2017.02.22 可以练习,每当这个时候,脑袋就犯困,我这脑袋真是神奇呀,一说让你做事情,你就犯困,你可不要太...
    Carden阅读 5,239评论 0 1
  • 编者按:由刘宇昆翻译,美国最权威的科幻奇幻出版公司之一Tor Books出版的《三体》,近日获得了美国总统奥巴马的...
    不存在日报阅读 4,585评论 0 1
  • 餐前叨叨: 无数次骑车上班路上,历经春夏秋冬梧桐树的四季更替。总念,什么时候拍拍春之梧桐、夏之梧桐、秋之梧桐...
    藤花旧馆阅读 2,540评论 1 3

友情链接更多精彩内容