UICollectionViewCell 重用导致不正确的 UISwitch 状态

Posted

技术标签:

【中文标题】UICollectionViewCell 重用导致不正确的 UISwitch 状态【英文标题】:UICollectionViewCell reuse causing incorrect UISwitch state 【发布时间】:2019-01-26 07:00:51 【问题描述】:

我无法找到解决此问题的方法。 我在UICollectionViewCell 中使用UISwitch,并且我正在传递一个布尔变量来设置开关。

条件是所有单元中一次只有一个开关必须打开。 但是当我打开一个开关时,另一个随机开关的色调会发生变化,这意味着它的状态发生了变化。

默认情况下,故事板中的开关状态为 ON,即使我将其设置为 OFF,也没有任何变化。

我不知道为什么会这样。

这是我的 cellForItemAtIndexPath 代码

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AddEditItemPopupView.cellId, for: indexPath) as! DiscountCollectionViewCell
        cell.delegate = self

        let currentDiscount = allDiscounts[indexPath.item]
        let shouldApplyDiscount = updatedDiscountId == currentDiscount.id
        cell.updateCellWith(data: currentDiscount, applyDiscount: shouldApplyDiscount)
        return cell
    

单元类的代码

func updateCellWith(data: DiscountModel, applyDiscount: Bool) 
        let name = data.title.replacingOccurrences(of: "Discount ", with: "")
        self.titleLabel.text = String(format: "%@ (%.2f%%)", name, data.value)
        self.switchApply.isOn = applyDiscount
        self.switchApply.tag = data.id
    

数据源包含DiscountModel 的对象,如下所示:


    id: Int!
    title: String!
    value: Double!

cell类内的开关值改变方法:

@IBAction func switchValueChanged(_ sender: UISwitch) 
        if sender.isOn 
            self.delegate?.switchValueDidChangeAt(index: sender.tag)
        
        else
            self.delegate?.switchValueDidChangeAt(index: 0)
        
    

视图控制器类中的委托方法:

func switchValueDidChangeAt(index: Int) 
        self.updatedDiscountId = index
        self.discountCollectionView.reloadData()
    

【问题讨论】:

如果在没有滚动的情况下发生这种情况,则可能不是单元格重用。它是静态的还是动态的集合视图? 还有,什么是switchApply? @Chris switchApply 是 collectionViewCell 中 UISwitch 的一个出口。它是一个动态集合视图,当前仅包含 4 个适合 collectionView 宽度的单元格,是的,这是在不滚动的情况下发生的。那么是什么导致了这个问题呢? 我觉得这两行可能是问题所在(但不确定):let currentDiscount = ...let shouldApplyDiscount = ... 你所做的有些问题。当您单击开关时,它会启动动画,但您会立即重新加载单元格,重置isOn,因此取消动画。我会尝试if switchApply.isOn != applyDiscount switchApply.isOn = applyDiscount DispatchQueue.main.async self.switchApply.isOn = applyDiscount 。一种可能的解决方案是禁用开关上的交互并改为处理整个单元格上的点击(选择)。 【参考方案1】:

我建议对您的代码进行一些改进;

重新加载整个集合视图有点像霰弹枪 由于可能不应用折扣,因此您可能应该为您选择的折扣使用可选项,而不是“0” 使用Tag 通常会出现问题

我会使用类似的东西:

var currentDiscount: DiscountModel? = nil

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AddEditItemPopupView.cellId, for: indexPath) as! DiscountCollectionViewCell
    cell.delegate = self

    let item = allDiscounts[indexPath.item]
    self.configure(cell, forItem: item)

    return cell


func configure(_ cell: DiscountCollectionViewCell, forItem item: DiscountModel) 
    cell.switchApply.isOn = false
    let name = item.title.replacingOccurrences(of: "Discount ", with: "")
    self.titleLabel.text = String(format: "%@ (%.2f%%)", name, item.value)

    guard let selectedDiscount = self.currentDiscount else 
        return
    

    cell.switchApply.isOn = selectedDiscount.id == item.id


func switchValueDidChangeIn(cell: DiscountCollectionViewCell, to value: Bool) 
    if value 
        if let indexPath = collectionView.indexPath(for: cell) 
           self.currentDiscount = self.allDiscounts[indexPath.item]
        
     else 
        self.currentDiscount = nil
    
    for indexPath in collectionView.indexPathsForVisibleItems 
        if let cell = collectionView.cellForItem(at: indexPath) 
            self.configure(cell, forItem: self.allDiscounts[indexPath.item])
        
    

在你的牢房里:

@IBAction func switchValueChanged(_ sender: UISwitch) 
    self.delegate?.switchValueDidChangeIn(cell:self, to: sender.isOn)

【讨论】:

以上是关于UICollectionViewCell 重用导致不正确的 UISwitch 状态的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionViewCell 重用问题

带有 UICollectionViewCell 的可重用 UITableViewCell

重用 UICollectionView 中的单元格时,会短暂显示重用 UICollectionViewCell 的旧内容

带有重用标识符的 UICollectionViewCell 初始化

注册大量 UICollectionViewCell 类以在 UICollectionView 中重用

iOS - 图像未加载到可重用的 UICollectionViewCell 上