这是一个在日常开发中经常会遇到的问题。先来看看产生问题的代码:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell? = nil
cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
let segment = UISegmentedControl(items: ["value1", "value2"])
segment.frame = CGRect.init(x: 8.0, y: 9.5, width: kScreenWidth - 16.0, height: 25.0)
segment.selectedSegmentIndex = tempIndex
segment.addTarget(self, action: #selector(segmentValueDidchanged(sender:)), for: .valueChanged)
cell!.contentView.addSubview(segment)
return cell!
}
@objc func segmentValueDidchanged(sender: UISegmentedControl) {
tempIndex = sender.selectedSegmentIndex
tableView.reloadData()
}
我的目标是想在 cell 上添加一个 segmentedControl,segmentedControl 的选定值由一个外部变量 tempIndex 来指定。同时,在其点击事件中重载 tableView。但是运行上述代码,当切换 segmentedControl 时,你会发现 cell 上的 view 被遮挡了。原因是因采用了 tableView 的复用,从队列中拿过来的复用 cell 上已经有添加的 segmentedControl,在这基础上会再创建一个 segmentedControl 添加上去。
那该如何解决这个问题呢?
方法一
在 cell 的 contentView 添加子视图前先删掉其上所有的子视图:
_ = cell!.contentView.subviews.map { $0.removeFromSuperview() }
// 添加子视图的代码
当子视图的个数很多时,从性能角度讲不推荐该方法。
方法二
自定义 UITableViewCell:
class MyCell: UITableViewCell {
var segment: UISegmentedControl!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
segment = UISegmentedControl(items: ["value1", "value2"])
segment.frame = CGRect.init(x: 8.0, y: 9.5, width: kScreenWidth - 16.0, height: 25.0)
self.contentView.addSubview(segment)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: MyCell? = nil
cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? MyCell
if cell == nil {
cell = MyCell(style: .default, reuseIdentifier: "cell")
}
cell!.segment.selectedSegmentIndex = tempIndex
cell!.segment.addTarget(self, action: #selector(segmentValueDidchanged(sender:)), for: .valueChanged)
return cell!
}
当需要添加很多子视图时,推荐使用该方法。
方法三
设置子视图的 tag 值,并通过 viewWithTag 方法获取子视图。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell? = nil
cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
if let segment = cell!.contentView.viewWithTag(888) as? UISegmentedControl {
// 已经添加了该子视图
segment.selectedSegmentIndex = tempIndex
} else {
let segment = UISegmentedControl(items: ["value1", "value2"])
segment.frame = CGRect.init(x: 8.0, y: 9.5, width: kScreenWidth - 16.0, height: 25.0)
segment.selectedSegmentIndex = tempIndex
segment.tag = 888
segment.addTarget(self, action: #selector(segmentValueDidchanged(sender:)), for: .valueChanged)
cell!.contentView.addSubview(segment)
}
return cell!
}
我个人推荐这种方法。