【问题标题】:Animate isHighlighted state of an imageView inside a cell of a collection view在集合视图的单元格内设置 imageView 的动画 isHighlighted 状态
【发布时间】:2018-12-13 23:40:42
【问题描述】:

我在集合视图的单元格内遇到isHighlighted imageView 状态的问题:我无法按照我的目标设置两个图像之间的过渡动​​画。

我的收藏视图的每个自定义单元格都有 3 个视图:

  1. 一个 UIImageView :具有突出显示和未突出显示的相关 .png 的背景图像
  2. 第二个 UIImageView :另一个带有突出显示和未突出显示的相关 .png 的图像作为前一个 UIImageView 的子视图
  3. 自定义 UILabel:文本标签

当我触摸单元格时,两个 ImageView 都会立即移动到突出显示状态,但我希望它们转换到这个状态(一个简单的 CrossDissolve 转换)

我尝试了 2 种不同的方法:在自定义单元格类中覆盖 isSelected 方法并将动画放入 collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)

覆盖 isSelected 属性:

    override var isSelected: Bool {
        didSet {
            UIView.transition(with: cellImageView, duration: 1, options: .transitionCrossDissolve, animations: {
                self.cellImageView.setNeedsLayout()
                self.cellImageView.layoutIfNeeded()
                self.cellImageView.isHighlighted = self.isSelected
            })
        }
    }

通过这种方式,当我单击模拟器中的单元格时,无论是单元格被选中还是失去选中状态时,我都不会看到动画,除非我单击并按住 一个单元格:然后我得到一个前一个单元格失去其选定单元格的动画(换句话说,我有前一个选定的 imageView 从isHighlighted(true) 到isHighlighted(false) 的过渡)。

didSelectItemAt indexPath 方法

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let cell = collectionView.cellForItem(at: indexPath) as! SubMenuCell
        UIView.transition(with: cell, duration: 1.0, options: .transitionCrossDissolve, animations: 
            cell.setNeedsLayout()
            cell.layoutIfNeeded()
            cell.cellImageView.isHighlighted = cell.isSelected
        })
    }

此方法在单元格被选中时不会触发动画,但在单元格从isSelected(true) 移动到isSelected(false) 时会提供过渡动画:换句话说,我看到之前选择的单元格淡出 并且我没有看到选定的单元格淡入。

我将不胜感激任何关于它为什么不起作用以及如何修复它的提示!

感谢大家花时间阅读和回复! 最好的,

【问题讨论】:

  • 你已经实现了didSelectItemAt。但是didDeselectItemAt呢?
  • 感谢@Rob 抽出宝贵时间!我假设实现didDeselectItemAt 会触发我想要的相反结果,不幸的是这已经是我所拥有的。但我确实尝试实现你的建议,无论有没有didSelectItemAt 方法,在这两种情况下,根本没有动画。

标签: ios swift uicollectionview uiviewanimationtransition


【解决方案1】:

感谢大家花时间思考我的问题。 通过进一步调查,我决定检查 3 个事件是如何以及何时触发的,即cell.isHighlighted、cell.isSelected 和collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath),实际上我发现了一些非常有趣的事情。让我总结一下:

当您在集合视图中触摸一个单元格 (cell1) 时,会出现以下事件:

  1. cell1.isHightlighted 设置为 true
  2. cell1.isHightlighted 设置为 false
  3. cell1.isSelected 设置为true,它会回调cell1.isHighlighted 属性
  4. 最后调用collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)方法

现在当您在集合视图中触摸另一个单元格(cell2)时,会发生以下事件:

  1. cell2.isHighlighted 设置为 true
  2. cell1.isSelected 设置为false,它回调cell1.isHightlighted 属性
  3. cell2.isHighlighted 设置为 false
  4. cell1.isSelected 再次设置为 false (!)
  5. cell2.isSelected 设置为true,它回调cell2.isHighlighted 属性
  6. 最后collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 方法是 叫

考虑到这一点,我得出的结论是,在集合视图方法中以 isHighlighted 状态运行过渡动画永远不会按预期工作,因为在到达方法之前已经设置了属性。

获得我发现的两个动画(isHighlightedtrue 和false)的一种解决方案是对我的自定义集合视图单元格的isHighlighted 和isSelected 的属性观察者采取行动,如下所示:

override var isHighlighted: Bool {
        willSet {
            if newValue == true {
                UIView.transition(with: cellImageView, duration: 1.0, options: .transitionCrossDissolve, animations: {
                    self.cellImageView.isHighlighted = newValue
                })
            }
        }
    }
    
 override var isSelected: Bool {
        willSet {
            if newValue == false {
                UIView.transition(with: cellImageView, duration: 1.0, options: .transitionCrossDissolve, animations: {
                    self.cellImageView.isHighlighted = newValue
                })
            }
        }
    }

我希望它对您有所帮助,并再次感谢所有花了一些时间试图弄清楚它的人! 如果有人找到更优雅的解决方案,请不要犹豫发布!!! 最好的,

【讨论】:

    【解决方案2】:

    我不相信,但我认为您可能还想覆盖;

    override func setSelected(_ highlighted: Bool, animated: Bool)
    

    在您的UICollectionViewCell 以及isSelected 属性中,因此在func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 中您的动画代码。

    *注意isHighlighted 和isSelected 之间也有区别,您在问题中说isHighlighted,但在您的实现中利用了isSelected。

    【讨论】:

    • 谢谢@Daniel!我的回答中解释了调用我发现的方法的问题:调用事件的顺序...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    相关资源
    最近更新 更多