在不使用 reload 方法的情况下调整 UICollectionView 的单元格

Posted

技术标签:

【中文标题】在不使用 reload 方法的情况下调整 UICollectionView 的单元格【英文标题】:Resize the cell of UICollectionView without the reload methods 【发布时间】:2016-07-02 07:42:42 【问题描述】:

如何在没有reload 方法的情况下调整UICollectionView 的单元格大小? 只想在某些事件上调用以下方法。我不想重新加载 UICollectionView 或其任何部分或行。

   func collectionView(collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                           sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 

【问题讨论】:

【参考方案1】:

我通过以下代码行得到了我的问题的解决方案。

collectionView?.collectionViewLayout.invalidateLayout()

注意要为这种调整大小设置动画,请使用 UIView.animate

let duration: TimeInterval = 0.3
UIView.animate(withDuration: duration, animations: 
    collectionView.collectionViewLayout.invalidateLayout() 
)

【讨论】:

如何使用动画来做到这一点? 这似乎也导致内容偏移设置为零?!?有什么办法可以防止这种情况发生? 这太棒了!谢谢【参考方案2】:

我可以确认 Payal Maniyar 的解决方案也适用于 UICollectionCompositional 布局。 在我的情况下,我有一个 CollectionViewCell,它只嵌入了一个 UITextView。组合布局正确计算出单元格中文本视图的初始大小。 (旁注:您可以通过禁用 UITextView 内的滚动来做到这一点,因为它已经在另一个可滚动视图内)。问题是当用户直接输入文本视图时,我想改变单元格的高度而不重新加载它。我想避免重新加载单元格有两个原因。 a) 重新加载的单元格在用户键入时闪烁,b) 文本视图失去焦点;因此,迫使用户再次单击文本视图以继续键入。所以我的解决方案如下:

    我有一个单元格,里面只有 UITextView,其中单元格也是 UITextView 的委托:

    class MyCollectionCell: UICollectionViewCell 
      @IBOutlet private weak var myTextView: UITextView!
      //this local variable used to determine if the intrinsic content size has changed or not
      private var textViewHeight: CGFloat = .zero
      ...
      ...
      override func awakeFromNib() 
       super.awakeFromNib()
       myTextView.delegate = self
      
      ...
      ...
    
    

    将此单元格与 UITextViewDelegate 一致

    extension MyCollectionCell: UITextViewDelegate  
    
    func textViewShouldBeginEditing(_ textView: UITextView) -> Bool 
      //this assumes that collection view already correctly laid out the cell
      //to the correct height for the contents of the UITextView
      //textViewHeight simply needs to catch up to it before user starts typing
      let fittingSize = textView.sizeThatFits(CGSize(width: myTextView.frame.width, height: CGFloat.greatestFiniteMagnitude))
      textViewHeight = fittingSize.height
    
      return true
    
    
    func textViewDidChange(_ textView: UITextView) 
      //flag to determine whether textview's size is changing
      var shouldResize = false
      //calculate fitting size after the content has changed
      let fittingSize = textView.sizeThatFits(CGSize(width: myTextView.frame.width, height: CGFloat.greatestFiniteMagnitude))
    
      //if the current height is not equal to 
      if textViewHeight != fittingSize.height 
        shouldResize = true
        //save the new height 
        textViewHeight = fittingSize.height
      
    
      //notify the cell's delegate (most likely a UIViewController) 
      //that UITextView's intrinsic content size has changed
      //perhaps with a protocol such as this:
      delegate?.textViewDidChange(newText: textView.text, alsoRequiresResize: shouldResize)
    
    

    然后当代理收到通知时,可能会保存更新的文本并更新布局,如下所示:

    myCollectionView.collectionViewLayout.invalidateLayout()
    

此解决方案的最佳部分是您不必调用 collectionView(_:layout:sizeForItemAt:) 来调整单元格的大小,因为您一开始没有使用笨重的 FlowLayout。

干杯!

【讨论】:

我也在使用组合布局,遗憾的是,这对我来说并不完美。当我使布局无效时,可悲的是,滚动位置发生了变化。我什至尝试使一个对我也不起作用的特定部分无效:( @NikhilMuskur 关于组合布局,看起来dataSource.apply(snapshot, animated: animated) 应该足以代替invalidateLayout()

以上是关于在不使用 reload 方法的情况下调整 UICollectionView 的单元格的主要内容,如果未能解决你的问题,请参考以下文章

python如何在不损失质量的情况下调整(缩小)图像的大小

有啥方法可以在不重新加载的情况下更改标头 URL? [复制]

如何在不改变文本透明度的情况下为 UILabel 设置背景图像并调整其 alpha?

在不损失质量的情况下调整图像大小

在不损失任何质量的情况下调整图像大小[关闭]

如何在不重新加载页面的情况下重新启动 Angular 应用程序?