UICollectionViewCell - 当其内容改变时动画单元格高度改变

Posted

技术标签:

【中文标题】UICollectionViewCell - 当其内容改变时动画单元格高度改变【英文标题】:UICollectionViewCell - animate cell height change when its content changes 【发布时间】:2020-06-17 14:18:01 【问题描述】:

我有一个非常简单的UICollectionView,使用 ios 13 的UICollectionViewCompositionalLayout。单元格有一个垂直的UIStackView,当您按下“切换详细信息”按钮时,我只需更改detailsViewisHidden 值。当单元格然后通知视图控制器它需要执行collectionView.collectionViewLayout.invalidateLayout() 时,基本上一切正常:详细信息视图被打开和关闭。但它没有动画,所以看起来有点刺耳。

class ViewController: UIViewController 
  @IBOutlet private var collectionView: UICollectionView!

  override func viewDidLoad() 
    super.viewDidLoad()
    collectionView.collectionViewLayout = createLayout()
  

  private func createLayout() -> UICollectionViewLayout 
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(200))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)

    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(200))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

    let section = NSCollectionLayoutSection(group: group)
    section.contentInsets = .init(top: 16, leading: 16, bottom: 16, trailing: 16)
    section.interGroupSpacing = 16

    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
  


extension ViewController: UICollectionViewDataSource 
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return 10
  

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
    cell.resize =  [weak self] in
      UIView.animate(withDuration: 2) 
        self?.collectionView.collectionViewLayout.invalidateLayout()
      
    
    return cell
  


class Cell: UICollectionViewCell 
  @IBOutlet private var detailsView: UIView!

  var resize: (() -> Void)?

  override func awakeFromNib() 
    super.awakeFromNib()
    contentView.layer.cornerRadius = 10
  

  @IBAction private func toggleDetails() 
    detailsView.isHidden.toggle()
    resize?()
  

复制项目:https://github.com/kevinrenskers/CellHeight.

如何为这个细节视图的切换设置动画,以便高度变化动画?可以与UIStackView 结合使用并显示/隐藏其子视图吗?请注意,细节视图在现实世界的应用程序中没有固定的高度,所以我不能只在两个固定值之间切换单元格高度。

【问题讨论】:

您使用集合视图而不是表格视图是否有原因? 是的。在真正的应用程序中,我在 collectionview 中也有水平滚动部分,这正是 UICollectionViewCompositionalLayout 的完美之处。 嗯...我在集合视图方面做得很少,部分原因是(我的印象是)管理单元格大小/调整大小非常困难。你可能想看看这个:raywenderlich.com/7246-expanding-cells-in-ios-collection-views——不太一样,但可能会给你一个实现的方向。除非您的经验不同,否则我的方法 - 因为 tableview 单元格展开/折叠非常容易 - 将使用 tableview,根据需要在 tableview 单元格中嵌入“水平滚动”集合视图(评论,而不是解决方案)。 如果你要对单元格的高度进行动画处理(将当前单元格更改为新单元格,甚至使用CGAffineTransform)然后在动画完成调用invalidateLayout,那么collectionView 有重新计算项目的大小 我无法让它工作,不。只需在示例项目中尝试它,如果你让它工作就提交它作为答案:) 【参考方案1】:

随着集合视图的动画化,我将您的存储库提供给您并进行一些更改。

https://github.com/lebaotrung93/CellHeight

它有效。但是使用 UIStackView,由于其自​​身的行为,似乎很难在 CollectionView 中管理它的大小。

【讨论】:

感谢您的回答和代码!但是动画看起来很糟糕,并且您禁用了 UICollectionViewCompositionalLayout 代码。再次启用它仍然可以正常工作,但动画仍然很糟糕:/我会在没有stackview的情况下尝试它。 是的,去掉stackview让动画效果好很多。它会自动调整大小,所以我认为在重新加载时,事件只是一行,其他人仍然调用 reload !!?。【参考方案2】:

我相信你应该在动画块之外调用collectionView.collectionViewLayout.invalidateLayout(),然后在动画块中调用self?.collectionView.layoutIfNeeded()

【讨论】:

我其实在上届WWDC期间就这个问题和苹果工程师打过电话,基本上没有解决办法。

以上是关于UICollectionViewCell - 当其内容改变时动画单元格高度改变的主要内容,如果未能解决你的问题,请参考以下文章

Swift 检测 UICollectionViewCell 是不是被拖到另一个 UICollectionViewCell 之上

当其文件夹为只读且文件不是只读时,文件属性为只读

在 UICollectionViewCell 中添加模糊

UICollectionViewCell与UIScrollView取消didSelectItemAtIndexPath

UICollectionViewCell 子类问题

重用 UICollectionViewCell