关于 tableView 复用 cell 上添加子视图导致重叠的问题

这是一个在日常开发中经常会遇到的问题。先来看看产生问题的代码:

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!
}

我个人推荐这种方法。

你可能感兴趣的:(关于 tableView 复用 cell 上添加子视图导致重叠的问题)