将单元格高度固定到 UICollectionView 高度

Posted

技术标签:

【中文标题】将单元格高度固定到 UICollectionView 高度【英文标题】:Pin cell height to UICollectionView height 【发布时间】:2018-07-19 12:00:08 【问题描述】:

我有一个水平的UICollectionView,它包含在一个垂直的UICollectionViewUICollectionView 标题中。垂直UICollectionView 的标题具有动态高度,该高度会因用户交互而变化(向下拖动外部UICollectionView 会展开它,向上滚动会折叠它)。水平的UICollectionView 受限于标题的大小,并且当标题的高度降低时,高度也会缩小。发生这种情况时,我会收到此错误

未定义 UICollectionViewFlowLayout 的行为,因为: 2018-07-19 13:42:09.959 IDAGIO[81891:2239798] 项目高度必须为 小于 UICollectionView 的高度减去部分插图 顶部和底部值,减去内容插入顶部和底部值。 2018-07-19 13:42:09.959 IDAGIO[81891:2239798] 请检查值 由代表返回。

因为UICollectionView 的高度缩小了,但它的单元格保持原来的大小,因此高于允许的大小(我只在向上滚动时收到此错误,因此它与任何插图无关,高度很好,它们只是在那个时间点不完全匹配)。

我已经尝试在每次收到垂直集合视图的滚动事件时调用collectionView.collectionViewLayout.invalidateLayout(),然后将集合视图大小返回到func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 但是布局更新总是有点太晚了,所以我仍然收到上述错误。而且它看起来很奇怪,因为单元格高度在视觉上也有点落后。

我的问题:有没有办法动态响应水平UICollectionView 的高度变化,以便单元格高度相应及时更新? (也许设置一些高度约束,自动保持单元格高度等于集合视图高度?)

我知道动态单元格大小,但这通常意味着将单元格限制为其内容的大小。我想要实现的是始终将单元格(及其内容)的高度限制为集合视图的高度。

【问题讨论】:

sizeForItemAtIndexPath 返回CGSizeMake(customWidth, collectionView.height); 并在每次达到新高度时重新加载您的收藏。 @TheTiger 正如我上面写的:我已经尝试过了,但是布局时间太长,所以没有及时更新。 您可以使用全局高度变量并将其传递给项目大小而不是 collectionView 高度。我的意思是在为集合视图的高度设置动画之前,只需使用全局变量将其重新加载到所需的高度。 【参考方案1】:

我自己找到了一个简单的解决方案,根本不需要传递或存储滚动偏移量: 只需继承 UICollectionViewFlowLayout,重写 shouldInvalidateLayout 并将 itemSize 设置为新边界的大小。

override func shouldInvalidateLayout(forBoundsChange: CGRect) -> Bool 
    if !forBoundsChange.size.equalTo(collectionView!.bounds.size) 
        itemSize = forBoundsChange.size
        return true
    
    return false

在 Swift 4.2 中

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool 
    if !newBounds.size.equalTo(collectionView!.bounds.size) 
        itemSize = newBounds.size
        return true
    
    return false

【讨论】:

【参考方案2】:

UICollectionView 有一个从UIScrollView 派生的属性,称为contentinsetadjustmentbehavior,如果您将collectionView 上的项目大小设置为collectionView 边界的大小,将其设置为false 应该可以解决您的问题。

因为 scrollView 可以调整 insets 从而改变 collectionView.adjustedContentInset

https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior

所以基本设置:

collectionView.contentInsetAdjustmentBehavior = .never

【讨论】:

【参考方案3】:

在滚动事件上重新加载数据是一种选择,但它绝对不是最好的选择,因为一次又一次地重新加载数据涉及所有计算。通过继承 UICollectionViewLayout 并在 prepare() 上进行所有计算,您可能会找到更好的解决方案。然后您可以使用委托将滚动偏移量传递给您的自定义布局并相应地调整单元格大小。

【讨论】:

谢谢,我试试看!

以上是关于将单元格高度固定到 UICollectionView 高度的主要内容,如果未能解决你的问题,请参考以下文章

uicollectionview 动态高度但固定宽度

具有固定高度的表格单元格中的自动布局多行标签

如何以编程方式将 UIImageView 缩放到固定宽度和灵活高度?

TextView的自动高度,在tableView的单元格中使用autolayout

使自定义单元格(使用自动布局创建)高度为零

Collectionview固定单元格间距