启用单元格预取时,UICollectionView deselectItem

时间:2016-10-22 14:26:12

标签: uicollectionview swift3 xcode8 ios10

在iOS 10.0上,UICollectionView默认预取单元格。这导致细胞准备好在屏幕上显示,但是被隐藏。这个question很好地描述了它。

以下代码将在其单元格可见或根本不存在时成功取消选择索引路径。如果单元格存在且被隐藏,则将取消选择索引路径,但单元格将停留在选定状态,直到重用为止。

collectionView!.deselectItem(at: indexPath, animated: false)

在iOS 9上或在iOS 10.0上使用isPrefetchingEnabled = false禁用预取时,此问题不会退出。

这是UICollectionView中的错误还是我误解了deselectItem应该如何工作?


以下是UICollectionViewController子类的完整代码,它通过以下步骤演示此行为:

  • 点击一个单元格,使其成为选中(红色)
  • 在屏幕外稍微滚动单元格
  • 点击"取消选择Cell"按钮
  • 在屏幕上滚动单元格
  • 观察它的外观如何选择
  • 点按其他单元格
  • 观察两个单元格的选择情况
  • 将第一个单元格远离屏幕再向后滚动
  • 观察第一个单元格最终未被选中的方式


import UIKit

private let reuseIdentifier = "Cell"

class CollectionViewController: UICollectionViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)

        let button = UIButton(frame: CGRect(x: 10, y: 30, width: 360, height: 44))
        button.backgroundColor = #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)
        button.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1), for: .normal)
        button.setTitleColor(#colorLiteral(red: 0.05882352963, green: 0.180392161, blue: 0.2470588237, alpha: 1), for: .highlighted)
        button.setTitle("Deselect Cell", for: .normal)
        button.addTarget(self, action: #selector(CollectionViewController.buttonPress), for: .touchUpInside)
        view.addSubview(button)
    }

    func buttonPress() {
        for indexPath in collectionView!.indexPathsForSelectedItems ?? [IndexPath]() {

            let cell = collectionView!.cellForItem(at: indexPath)
            NSLog("Deselecting indexPath: %@, cell: %@", indexPath.description, cell?.frame.debugDescription ?? "not visible")

            collectionView!.deselectItem(at: indexPath, animated: false)
        }
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 300
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
        cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
        cell.selectedBackgroundView = UIView(frame: cell.bounds)
        cell.selectedBackgroundView!.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
        return cell
    }
}

1 个答案:

答案 0 :(得分:1)

据我所知,这是UICollectionView中的一个错误,我自己也开了一个雷达。您可能也希望这样做以施加更大的压力。

即使在预取之前,集合视图也不会忘记取消选择不可见的单元格。即使cellForItemAtIndexPath:也声明它会为不可见的单元格返回nil

但是在预取之前,只要一个单元格离开内容视图,它就会被添加到重用池中,当你向后滚动时,你会得到一个重用的单元格,它会重置所选的状态。

现在,该单元格仍然被加载,并且在重新使用之前不会重置,通过进一步滚动,超出预取区域。

要解决此问题,您可以将prefetchingEnabled设置为NO并失去其优势,或在信号出现时更新选择状态 -

- (void)collectionView:(UICollectionView *)collectionView
       willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
  if (!cell.isSelected) {
    return;
  }

  if ([[collectionView indexPathsForSelectedItems] containsObject:indexPath]) {
    return;
  }

  cell.selected = NO;
}

这似乎不会降低性能。