CollectionView estimatedItemSize 未按预期工作

Posted

技术标签:

【中文标题】CollectionView estimatedItemSize 未按预期工作【英文标题】:CollectionView estimatedItemSize not working as expected 【发布时间】:2017-02-16 03:15:41 【问题描述】:

我尝试使用estimatedItemSize 动态调整collectionView 单元格的大小以适应它们的内容塔我遇到了一些不同设备尺寸的问题,特别是宽度没有调整大小,它只是保持与界面生成器中的大小相同.

我在 iPhone 7 上完成了 Interface Builder 的工作,因此屏幕宽度为 375。在我的故事板中,我有以下内容。

outerCollectionView 以 0 边距固定到 superView 的所有 4 个边 outerCollectionView 单元格的 w: 339 h:550

在这个单元格内我有:

innerCollectionView 以 0 边距固定到单元格的所有 4 个边 innerCollectionView 常量 w: 339 h: 550 添加到 IB 中

在我的 DataSource 和 Delegate 类中,我在 viewDidLoad 函数中定义了我的流布局:

    let width = UIScreen.main.bounds.size.width
    let height = UIScreen.main.bounds.size.height
    let flow = outerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
        flow.estimatedItemSize = CGSize(width: width - ((width / 18.75)), height: height / 4)
        flow.minimumLineSpacing = (width / 37.5)
        flow.sectionInset = UIEdgeInsets(top: (width / 37.5), left: (width / 37.5), bottom: (width / 37.5), right: (width / 37.5))

在包含“内部”集合的自定义单元格类中,我设置了一些常量约束并定义流布局以调整项目大小:

    // This is the correct screen size
    // let width = innerCollectionView.frame.size.width
    let width = UIScreen.main.bounds.size.width
    let flow = innerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
        flow.sectionInset = UIEdgeInsetsMake((width / 37.5), (width / 37.5), (width / 37.5), (width / 37.5))
        flow.itemSize = CGSize(width: (width / 6 - (width / 37.5)), height: (width / 6 - (width / 37.5)))
        flow.minimumInteritemSpacing = (width / 37.5)
        flow.minimumLineSpacing = (width / 37.5)

        innerCollectionHeight.constant = innerCollectionView.collectionViewLayout.collectionViewContentSize.height
        innerCollectionWidth.constant = innerCollectionView.collectionViewLayout.collectionViewContentSize.width

现在这一切工作正常,单元格垂直调整大小以在 iPhone 7 模拟器上很好地适应我的内容,显示正确填充的单列单元格。但是当我加大设备尺寸时,不会调整单元格的宽度。当我使用较小的设备时,我收到一大堆关于单元格宽度如何变大的 Xcode 错误,因为它没有调整大小,但没有显示。 (下图)

2017-02-16 12:53:49.632 ParseStarterProject-Swift[26279:394906] The behavior of the UICollectionViewFlowLayout is not defined because:
2017-02-16 12:53:49.632 ParseStarterProject-Swift[26279:394906] the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
2017-02-16 12:53:49.632 ParseStarterProject-Swift[26279:394906] Please check the values returned by the delegate.
2017-02-16 12:53:49.633 ParseStarterProject-Swift[26279:394906] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7be38920>, and it is attached to <UICollectionView: 0x7db03600; frame = (0 0; 320 504); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7d61a550>; layer = <CALayer: 0x7be95880>; contentOffset: 0, 0; contentSize: 320, 20> collection view layout: <UICollectionViewFlowLayout: 0x7be38920>.

显然我不能使用

flow.itemSize =

设置外部单元格的大小,因为我需要估计大小来调整垂直长度并拥抱内容。我只是想不通为什么宽度没有增加以适应屏幕尺寸??

大型设备 - 边距太大:CV 宽度 339

我构建的 iPhone 7 - 边距正常:CV 宽度 339

---- 编辑 -----

尝试覆盖 szeForItemAt 但没有任何变化。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 

    let width = self.view.frame.size.width
    let height = self.view.frame.size.height

    if collectionView == self.outerCollectionView 

        return CGSize(width: width - 100, height: height / 4)

     else 

        return  CGSize(width: (width / 6 - (width / 75)), height: (width / 6 - (width / 75)))
    

---- 编辑----

我可以编辑单元格的首选项目占用。使用压缩的高度选项并设置我自己的宽度大小,(width / 18.7) 是宽度减去之前定义的左右插图

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 

    let attributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes
    let width = UIScreen.main.bounds.size.width
    let desiredWidth = width - (width / 18.75)
    //let desiredWidth = systemLayoutSizeFitting(UILayoutFittingExpandedSize).width
    let desiredHeight = systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        attributes.frame.size.width = desiredWidth
        attributes.frame.size.height = desiredHeight

    return attributes

但这会填充如下图所示的约束,我认为这可能只是我运行的一个脚本,用于填充 UIViews 的顶角。但它也填满了单元格,因为它每行塞得更多。

屏幕较小,单元格类似问题:

【问题讨论】:

【参考方案1】:

解决方案是实现UICollectionViewDelegateFlowLayout并像这样调用sizeForItemAt

extension YourClass: UICollectionViewDelegateFlowLayout 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    //return size needed
    return CGSize(width: (width / 6 - (width / 37.5)), height: (width / 6 - (width / 37.5)))

在运行时返回的大小将是给项目大小的那个。

注意:在没有UICollectionViewDelegateFlowLayout 的情况下实现sizeForItemAt 将不会成功

【讨论】:

以上是关于CollectionView estimatedItemSize 未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

CollectionView 单元格出现在 collectionView 之外。

CollectionView 里面的 CollectionView | CollectionViewCell 自动布局错误

当collectionView折叠时隐藏collectionView内容

普通 CollectionView 单元格中的动态 CollectionView 单元格

CollectionView 嵌套在 Collectionview 中

- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath 未调用