为什么屏幕外的 UICollectionViewCells 不会更新?

Why won't UICollectionViewCells that are offscreen update?

我有一个 UICollectionView 以水平流布局显示自定义单元格;换句话说,一些内容被放置在屏幕边界之外。 此外,我有一个手势会触发 NSNotification,导致我的单元格中的某些元素(即主题)发生颜色变化。除了出现在屏幕边界之外的单元格不会全部更新为新的颜色变化之外,一切都完美无缺。有什么办法可以强制重绘吗?

在触发 NSNotification 时调用的函数中,我尝试使用 self.collectionView.reloadData()self.collectionView.setNeedsDisplay()self.collectionView.setNeedsLayout 重绘集合视图,但无济于事。我在自定义单元格 class 的 awakeFromNib() 中尝试了列表的最后两个,但什么也没有。

这是我的 cellForItemAtIndexPath:

的代码
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
            let cell = popularCollectionView!.dequeueReusableCellWithReuseIdentifier("popular", forIndexPath: indexPath) as! PopularPainting
            cell.thumbnail.image = paintings[indexPath.row].paintingImage
            cell.name!.text = paintings[indexPath.row].paintingName
            cell.price!.setTitle(paintings[indexPath.row].paintingPrice, forState: UIControlState.Normal)
            if cell.isDark {
                cell.name!.textColor = UIColor(red: 205/255, green: 205/255, blue: 205/255, alpha: 1)
                cell.price!.setTitleColor(self.kPaleBlue, forState: .Normal)
                self.popularCollectionView.reloadData()
            }

            return cell
}

有什么建议吗?

注意:滚动到屏幕外的内容并重复手势以更改主题非常有效,所以我不知道发生了什么。

您假设集合视图中的每个项目都存在屏幕外的单元格是不正确的。事实上,table 视图和集合视图会重复使用滚动到屏幕外的单元格,以便新单元格出现在屏幕上,因此存在的单元格只有一屏多一点。

您可以在通知触发后调用 reloadData。但是您需要确保 collectionView:itemForRowAtIndexPath: 的实现将正确配置随后在屏幕上滚动的单元格。这可能意味着在通知触发后将状态更改保存在 属性 中,并在 collectionView:itemForRowAtIndexPath:.

中配置单元格时检查 属性

为了解决“无法使用 cellForItemAtIndexPath: 访问视图,但在屏幕上显示之前不会被回收”的问题,您可以将视图初始化逻辑从 collectionView:cellForItemAtIndexPath: 移动到 collectionView:willDisplayCell:forItemAtIndexPath:.

例如,您原来的位置:

override func collectionView(
    _ collectionView: UICollectionView,
    cellForItemAt indexPath: IndexPath
) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(
        withReuseIdentifier: self.reuseIdentifier,
        for: indexPath
    )
    // Initialize cell
    return cell
}

您可以将其替换为:

override func collectionView(
    _ collectionView: UICollectionView,
    cellForItemAt indexPath: IndexPath
) -> UICollectionViewCell {
    return collectionView.dequeueReusableCell(
        withReuseIdentifier: self.reuseIdentifier,
        for: indexPath
    )
}

override func collectionView(
    _ collectionView: UICollectionView,
    willDisplay cell: UICollectionViewCell,
    forItemAt indexPath: IndexPath
) {
    // Initialize cell
}

这确保如果 cellForItemAtIndexPath: returns nil,单元格将在下一次显示在屏幕上之前被 collectionView:willDisplayCell:forItemAtIndexPath: 正确初始化。