动态更改 CollectionView 的高度以适应内容大小时的错误结果

Posted

技术标签:

【中文标题】动态更改 CollectionView 的高度以适应内容大小时的错误结果【英文标题】:Wrong result when dynamically changing the height of the CollectionView to adapt to content size 【发布时间】:2021-01-05 22:50:15 【问题描述】:

在我的DetailViewController 中,我有两个collectionViews,我正在尝试动态更改它们的高度。我可以通过使用DetailViewController 中的观察者更改两个高度约束IBOutlets 来成功实现这一点。但是,如果我从 DetailViewController 推送另一个 ViewController 然后返回,则它不起作用。

这是“DetailViewController”中的代码

@IBOutlet weak var deadlineCollectionViewHeight: NSLayoutConstraint!
@IBOutlet weak var tasksCollectionViewHeight: NSLayoutConstraint!

private var CVcontentSizeObservation: [NSKeyValueObservation]?

private var initialCollectionViewsHeight: InitialCollectionViewsHeight?

override func viewDidLoad() 

     super.viewDidLoad()
     initialCollectionViewsHeight = InitialCollectionViewsHeight(deadlines: 
     deadlineCollectionViewHeight.constant, tasks: tasksCollectionViewHeight.constant)
     observeCollectionView()

 

private func observeCollectionView()

    CVcontentSizeObservation = [

         deadlinesCollectionView.observe(\.contentSize, options: .new, changeHandler: [weak self] (cv, _) in
        
               guard let self = self else  return 
            
               if cv.collectionViewLayout.collectionViewContentSize.height < self.initialCollectionViewsHeight!.deadlines
            
                    self.deadlineCollectionViewHeight.constant = cv.collectionViewLayout.collectionViewContentSize.height
            
                
         ),
    
        tasksCollectionView.observe(\.contentSize, options: .new, changeHandler: [weak self] (cv, _) in
        
             guard let self = self else  return 
            
             if cv.collectionViewLayout.collectionViewContentSize.height < self.initialCollectionViewsHeight!.tasks
            
                     self.tasksCollectionViewHeight.constant = cv.collectionViewLayout.collectionViewContentSize.height
             
       )
   ]



private struct InitialCollectionViewsHeight
    var deadlines: CGFloat
     var tasks: CGFloat

问题

如果我从家庭 VC 推送 DetailViewController,这会正常工作,但如果我从那里推送另一个 VC 然后返回,我会得到错误的结果。

第一张图片显示了DetailViewController 最初被推送后的正确行为。但是,如果我按下“编辑按钮”按钮并按下一个新的 VC,则在我将其关闭并从堆栈中弹出 VC 后会得到错误的结果(即:我返回到DetailViewController),如中所示第二张图片

【问题讨论】:

尽管我不确定您为什么会遇到这种行为,但我可能会采用不同的方法:UICollectionView 的想法本身就是动态的。您不需要根据集合视图的内容大小手动更改约束。相反,您应该使用约束来指定您的内容视图可以“存在”的合法区域,然后它应该自行决定如何调整自己的大小。 @Petar 问题是,一旦我设置了collectionview 高度约束,框架就会固定并且高度不会改变。我错了吗? 是的,忽略我的悲伤——你不能用滚动视图来做到这一点,因为它们没有内在的内容大小。由于您要添加 2 个滚动视图,您应该指定至少其中一个的高度。你写的东西是有道理的,我认为问题出在其他地方 - 看起来整个视图都被打破了:注意信息标签也不在原来的位置。愿意分享您的代码吗? 【参考方案1】:

据我了解,您正在尝试使集合视图适合其高度。由于 UICollectionViewLayout 的行为,使用约束方法可能会带来一些问题。

我建议使用这种方法:

class AutoSizingCollectionView : UICollectionView

    override func layoutSubviews() 
        super.layoutSubviews()
        
        if (self.bounds.size.equalTo(self.intrinsicContentSize)) 
            self.invalidateIntrinsicContentSize()
        
    
    
    override var intrinsicContentSize: CGSize
    
        return self.collectionViewLayout.collectionViewContentSize
    

使用AutoSizingCollectionView 类交换您的CollectionViews,它们将使用IntrinsicContentSize 方法自动将其高度缩放到其内容大小。它将允许您轻松地将底部集合视图固定到第一个视图的底部。

希望能解决你的问题。

【讨论】:

感谢您的回复,这在某些情况下有效(但是我不得不从情节提要中删除高度限制)。事实上,当我的元素少于三个时,我尝试添加通过按“添加截止日期”创建一个新单元格,看起来内容大小保持不变,因此集合视图尝试在之前两个单元格的空间中容纳三个单元格。如果然后我弹出 VC 然后再次推送它,则内容大小计算正确。 添加或删除元素时,您可能需要invalidateLayout 处理这种情况,并可能调用 layoutIfNeeded 以便重新计算所有内容。否则布局会被缓存,它们将无法正确重新计算 contentSize。并且高度限制应该全部删除,否则自动调整大小将无法正常工作。 IntrinsicContentSize 仅在元素未定义高度约束时有效。 试试看,我已经更新了问题,但当添加新元素时,我仍然无法让 collectionview 增加内容大小。当我删除一个单元格时,我还得到一个单元格高度增加的奇怪行为 谢天谢地,我设法找到了答案,明天我会用解决方案更新我的问题。这是一个非常简单的错误——在 SizeforItemAt 中,我返回了一个基于 collectionViewframe (collectionView.frame/3) 的高度,并且我已更改为一个固定数字。谢谢!!! @LucaSfragara 所以你的原始代码在我发布的解决方案结束时工作?

以上是关于动态更改 CollectionView 的高度以适应内容大小时的错误结果的主要内容,如果未能解决你的问题,请参考以下文章

根据单元格的不更改单元格高度动态更改 UICollectionView 高度

使 CollectionView 和 TableView 高度动态化

UITableViewCell 无法根据它包含的动态 CollectionView 调整高度

如何使用自动布局动态调整具有固定宽度的collectionview单元格高度?

计算 NSString 高度以在 collectionView 单元格中使用

如何根据其中的内容创建具有动态高度的集合视图?