本文是一个实例讲解
很多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
支持原创,版权所有
网友评论