滚动 UICollectionView 的不良做法

Posted

技术标签:

【中文标题】滚动 UICollectionView 的不良做法【英文标题】:Scrolling bad practice for UICollectionViews 【发布时间】:2017-02-16 13:14:19 【问题描述】:

我制作了一个水平滚动的 UICollectionView,我希望中间的单元格具有白色字体,而其余的为黑色。

如果我只使用 scrollViewDidEndDecelerating 突出显示中间单元格似乎比我同时使用 scrollViewWillBeginDecelerating 和 scrollViewDidEndDecelerating 突出显示中间单元格更多。这是不好的做法吗?

extension CurrencySelectorTableViewCell: UIScrollViewDelegate
    func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) 
        self.findCenterIndex()
    

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) 
        self.findCenterIndex()
    

顺便说一句,这段代码仍然不能像我想要的那样完美地动画,所以我愿意接受任何建议,如何使这个滚动机制尽可能平滑。

当 UICollectionView 开始滚动时,触发此功能:

func findCenterIndex() 
    let center = self.convert(self.collectionView.center, to: self.collectionView)
    let index = collectionView!.indexPathForItem(at: center)

    if let selectedIndex = index 
        self.selectedCell = selectedIndex.item
        self.collectionView.reloadData()
    

在重新加载 UICollectionView 时,位于中间的单元格中的标签看起来与其余部分不同:

func collectionView(_ collectionView: UICollectionView,
                             cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CurrencySelectorCollectionViewCell", for: indexPath) as! CurrencySelectorCollectionViewCell

    if (indexPath.item == self.selectedCell) 
        cell.currencyLabel.textColor = UIColor.white
        cell.currencyLabel.font = cell.currencyLabel.font.withSize(22)
     else 
        cell.currencyLabel.textColor = UIColor.black
        cell.currencyLabel.font = cell.currencyLabel.font.withSize(15)
    

    cell.currencyLabel.text = currencies[indexPath.item]

    return cell

现在它会跳动一点,因为它只会在滚动刚刚开始或刚刚停止时更改标签。我希望 UITextLabel 上的这种效果在整个滚动过程中不断发生。

【问题讨论】:

动画?你是说你在突出显示一个单元格,但后来你说你在触发动画,是什么? 很抱歉给您带来了困惑。现在我只是根据中间的单元格更改 UICollectionCell 中 UILabel 的文本颜色。我更喜欢在用户滚动水平展开的 UICollectionCells 时为这种效果设置动画。 @rutgerHujismans 你能添加你正在触发的动画代码吗? @rutgerhujismans 检查我的答案。 【参考方案1】:

在启动新动画之前尝试添加UILabel 层的removeAllAnimations():

[view.layer removeAllAnimations];

编辑:

根据您在问题中的编辑,您没有运行任何动画。你在UICollectionView 上调用reloadData,这是非常糟糕的做法。

你应该只是简单:

1:(错误选项)

仅使用 performBatchUpdates(_:completion:) 重新加载单元格

2:不错的选择

在单元格findCenterIndex 和cellForItem(at:) 中将单元格作为变量访问,只需对标签进行更新即可。

您还可以通过获取visibleCells 的数组来取消选择其他单元格,只需按照上述相同操作即可,但您会触发“取消选择”代码。您实际上可以在运行选择代码之前执行此操作。或者,只需在可见单元格上运行 for 循环并在循环中“取消选择”它们,然后在 CGPoint 中心选择一个,即可在一个操作中完成所有操作。

这样,您甚至不必重新加载您的 UICollectionView,这是最佳实践。您还可以避免闪烁和动画。

【讨论】:

好的,我会选择好的选择。我选择 reloadData 的原因是为了重置之前在中间的标签。 @RutgerHuijsmans 我也用该解决方案更新了答案。看看吧:) 好的,非常感谢这个作品!我不再重新加载数据。 UILabel 的变化仍然只发生在滚动运动结束时。这个感觉有点拖沓。有没有办法让这感觉更顺畅? @RutgerHuijsmans 抱歉忘了提你可能循环了很多次,因为滚动视图在 scrollViewWillBeginDecelerating 方法中移动的每个像素都会触发它,你需要做一些在那里进行检查以限制您的自定义代码和循环被触发的时间。使用两个属性 NSDate 和一个 BOOL 检查 NSDate 时间戳(可能只允许它从存储的 NSDate currentDate 或其他方法每 0.5 秒触发一次。 @RutgerHuijsmans 您的另一种选择是检查中心单元格是否与之前的单元格不同(使用标签或其他东西),并且仅在单元格不同或移动较远时触发“动画”够了。

以上是关于滚动 UICollectionView 的不良做法的主要内容,如果未能解决你的问题,请参考以下文章

这种不良做法/反模式的名称是啥?

强制整个网站使用HTTPS的良好做法或不良做法?

(Fortify) 类别:Android 不良做法:缺少 Google Play 服务更新的安全提供程序(1 个问题)

这是使用错误抑制运算符的不良做法吗?

捕获IllegalStateException的不良做法?备择方案?

HP Fortify:ASP.NET 不良做法:存储在会话中的不可序列化对象