如何为 UICollectionView 单元格选择设置动画

How to animate a UICollectionView cell selection

UICollectionView 的这些方法的 animated 参数是做什么的:

我知道我可以使用 UICollectionViewLayout 对象来动画更改。我也知道我可以使用 UICollectionViewDelegatedidSelectdidDeselect 方法来获取选定的单元格并应用动画。但是我找不到关于上述 animated 参数如何影响动画的任何信息。它会以任何方式影响布局动画吗?我的目标是创建一个 UICollectionView 子类,并允许消费者自定义在内部调用上述两个方法时是否应用动画。但是我不知道那些方法控制的是什么动画。

UICollectionViewselectItem(at:animated:scrollPosition:) 中的 animated 确定项目 to-be-selected 如果不在视图中或已经在所需位置,是否应滚动到动画时尚与否。
如果它在视图中,那么这个 animated 属性 并没有真正做任何事情,afaik。
deselectItem(at:animated:) 中的 animated 也一样。它什么都不做,就在那里。

我看到的唯一影响布局引擎的是,如果 collectionView 滚动并且您在 didSelectItemAt 中有动画,那么它会使这些动画无效。您将不得不延迟单元格中发生的动画(请参阅此答案中的最后一个示例)


如您所知,但对于其他人来说,如果您想为单元格选择事件设置动画,那么您必须在 collectionView(_:didSelectItemAt:) 委托中自己完成。

示例:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)

    //Briefly fade the cell on selection
    UIView.animate(withDuration: 0.5,
                   animations: {
                    //Fade-out
                    cell?.alpha = 0.5
    }) { (completed) in
        UIView.animate(withDuration: 0.5,
                       animations: {
                        //Fade-out
                        cell?.alpha = 1
        })
    }

}

如果用户点击一个单元格,上面的内容很好,但如果你以编程方式调用 selectItem(at:animated:scrollPosition:),它不会触发上面的 collectionView(_:didSelectItemAt:) 委托,你需要显式调用它 运行你的选择动画。

示例(Add-on 到上一个):

func doSelect(for aCollectionView: UICollectionView,
              at indexPath: IndexPath) {
    aCollectionView.selectItem(at: indexPath,
                               animated: true,
                               scrollPosition: .centeredVertically)

    //DispatchQueue after sometime because scroll animation renders
    //the animation block in `collectionView(_:didSelectItemAt:)` ineffective
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.27) { [weak self] in
        self?.collectionView(aCollectionView,
                             didSelectItemAt: indexPath)
    }
}

我建议用动画覆盖 UICollectionViewCellisHighlighted 属性。这样,如果用户点击一个单元格并停止思考下一步该做什么,动画状态将被保留。

    override var isHighlighted: Bool {
        didSet {
            toggleIsHighlighted()
        }
    }

    func toggleIsHighlighted() {
        UIView.animate(withDuration: 0.1, delay: 0, options: [.curveEaseOut], animations: {
            self.alpha = self.isHighlighted ? 0.9 : 1.0
            self.transform = self.isHighlighted ?
                CGAffineTransform.identity.scaledBy(x: 0.97, y: 0.97) :
                CGAffineTransform.identity
        })
    }