动态更改 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单元格高度?