未定义UICollectionViewFlowLayout的行为,因为单元格宽度大于collectionView宽度

Sha*_*bba 47 uicollectionview uicollectionviewcell uicollectionviewlayout ios9 xcode7-beta5

2015-08-18 16:07:51.523示例[16070:269647]未定义UICollectionViewFlowLayout的行为,因为:2015-08-18 16:07:51.523
示例[16070:269647]项目宽度必须小于UICollectionView的宽度减去左边和右边的值,减去左边和右边的内容值.
2015-08-18 16:07:51.524示例[16070:269647]相关的UICollectionViewFlowLayout实例是,并附加到; 动画= {position =; bounds.origin =; bounds.size =; }; layer =; contentOffset:{0,0}; contentSize:{1024,770}>集合视图布局:.2015-08-18 16:07:51.524示例[16070:269647]在UICollectionViewFlowLayoutBreakForInvalidSizes上创建一个符号断点,以便在调试器中捕获它.

这就是我得到的,我所做的是

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        return CGSizeMake(self.collectionView!.frame.size.width - 20, 66)
    }
Run Code Online (Sandbox Code Playgroud)

当我从横向旋转到纵向时,控制台仅在iOS 9中显示此错误消息,是否有人知道这是怎么回事?如果有解决方法?

截图

Air*_*ène 37

当您的集合视图调整为较小的宽度(例如,从横向模式到纵向模式),并且单元格变得太大而不适合时,就会发生这种情况.

为什么单元格变得太大,因为应该调用集合视图流布局并返回合适的大小?

collectionView(collectionView:UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath)

更新以包含Swift 4

@objc覆盖func collectionView(_ collectionView:UICollectionView,cellForItemAt indexPath:IndexPath) - > UICollectionViewCell {...}

这是因为没有调用此函数,或者至少不是直接调用此函数.

会发生什么是您的集合视图流布局子类不会覆盖该shouldInvalidateLayoutForBoundsChange函数,returns false默认情况下.

当此方法返回false时,集合视图首先尝试使用当前单元格大小,检测问题(记录警告),然后调用流布局以调整单元格的大小.

这意味着两件事:

1 - 警告本身并无害处

2 - 您可以通过简单地覆盖shouldInvalidateLayoutForBoundsChange函数来返回true来消除它.在这种情况下,当集合视图边界发生更改时,将始终调用流布局.

  • 从WWDC'18*UICollectionView*之旅中,提到即使**滚动**集合视图,也会调用此方法`shouldInvalidateLayoutForBoundsChange`.因此,扬声器特别提醒您在重写此方法时要小心,因为它经常被调用. (5认同)

小智 37

在故事板中选择 collectionview 转到大小检查器将估计大小更改为无


Nav*_*chi 21

代码 11

对我来说,原因是 CollectionView 的 Estimate 选项大小设置为 Automatic。这似乎是 XCode 11 中的默认行为。

因此,对于我在单元格中加载图像的我来说,由于图像的大小和自动选项(它想要根据图像的大小调整单元格的大小),单元格的宽度变得大于 CollectionView 的宽度。

通过将此选项设置为 None 问题解决了。

自动选项所在的位置

  • 救世主。!!对于 Xcode 11,这是最简单且完美的技巧。 (2认同)

Man*_*nav 9

我还看到当我们将EstimatedItemSize设置为automaticSize并且计算出的单元格大小小于50x50时会发生这种情况(注意:此答案在iOS 12时有效。也许更高版本已将其修复)。

也就是说,如果您通过将估计的项目大小设置为automaticSize常数来声明支持自定义单元格,则:

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
Run Code Online (Sandbox Code Playgroud)

并且您的单元格实际上小于50x50点,则UIKit会打印出这些警告。FWIW,最终调整了牢房的大小,并且警告似乎无害。

一种解决方法是用1x1的估计项目大小替换常量:

flowLayout.estimatedItemSize = CGSize(width: 1, height: 1)
Run Code Online (Sandbox Code Playgroud)

这不会影响自调整大小支持,因为正如所estimatedItemSize提到的文档所述:

将其设置为任何其他值会使集合视图使用单元格的preferredLayoutAttributesFitting(_ :)方法查询每个单元格的实际大小。

但是,它可能/可能不会影响性能。

  • 如果这些天 covid-19 不再和我们在一起,我发誓我会去任何你现在在的地方,拥抱你,哈哈,你拯救了我的一天,这让我发疯。看了很多关于设置自动调整单元格大小的教程,甚至在我自己的项目中也正确设置了它们,但是......它们都超过了 50pt。非常感谢! (10认同)

Hlu*_*ung 6

我正在使用其子类UICollectionViewFlowLayout并使用其itemSize属性来指定单元格大小(而不是collectionView:sizeForItemAtIndexPath:委托方法).每当我将屏幕旋转到较短的宽度时(例如风景 - >肖像),我就会收到这个巨大的警告.

我能够通过两个步骤来修复它.

第1步:UICollectionViewFlowLayout子类的prepareLayout()功能,移动super.prepareLayout()在那里self.itemSize设置.我认为这使超类使用正确的itemSize值.

import UIKit

extension UICollectionViewFlowLayout {

  var collectionViewWidthWithoutInsets: CGFloat {
    get {
      guard let collectionView = self.collectionView else { return 0 }
      let collectionViewSize = collectionView.bounds.size
      let widthWithoutInsets = collectionViewSize.width
        - self.sectionInset.left - self.sectionInset.right
        - collectionView.contentInset.left - collectionView.contentInset.right
      return widthWithoutInsets
    }
  }

}

class StickyHeaderCollectionViewLayout: UICollectionViewFlowLayout {

  // MARK: - Variables
  let cellAspectRatio: CGFloat = 3/1

  // MARK: - Layout
  override func prepareLayout() {
    self.scrollDirection = .Vertical
    self.minimumInteritemSpacing = 1
    self.minimumLineSpacing = 1
    self.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: self.minimumLineSpacing, right: 0)
    let collectionViewWidth = self.collectionView?.bounds.size.width ?? 0
    self.headerReferenceSize = CGSize(width: collectionViewWidth, height: 40)

    // cell size
    let itemWidth = collectionViewWidthWithoutInsets
    self.itemSize = CGSize(width: itemWidth, height: itemWidth/cellAspectRatio)

    // Note: call super last if we set itemSize
    super.prepareLayout()
  }

  // ...

}
Run Code Online (Sandbox Code Playgroud)

请注意,当屏幕旋转停止工作时,上述更改将以某种方式使布局大小更改.这是第2步的用武之地.

第2步:将其放在包含集合视图的视图控制器中.

  override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    collectionView.collectionViewLayout.invalidateLayout()
  }
Run Code Online (Sandbox Code Playgroud)

现在警告消失了:)


一些说明:

  1. 确保您正在向collectionView添加约束而不使用 collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

  2. 确保您没有调用invalidateLayout,viewWillTransitionToSize() 因为横向中边对边单元格的宽度大于纵向中集合视图的框架宽度.见下面的参考文献

参考


小智 6

对于 Xcode 11,上述方法都不适合我。

结果证明需要在集合视图大小面板中将估计大小设置为无。

见:https : //forums.developer.apple.com/thread/123625


小智 5

它的发生是因为你的集合视图单元格的宽度大于旋转后的集合视图宽度.假设您有一个1024x768的屏幕并且您的集合视图填满了屏幕.当您的设备是横向时,您的单元格的宽度将是self.collectionView.frame.size .width - 20 = 1004并且它大于集合视图的宽度(纵向)= 768.调试器说"项目宽度必须小于UICollectionView的宽度减去部分插入左右值,减去内容插入左边和正确的价值观".


小智 5

我已经使用解决了这个问题safeAreaLayoutGuide

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

    return CGSize(width: (view.safeAreaLayoutGuide.layoutFrame.width), height: 80);
}
Run Code Online (Sandbox Code Playgroud)

并且您还必须重写此功能才能正确支持纵向和横向模式。

 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    collectionView?.collectionViewLayout.invalidateLayout();
}
Run Code Online (Sandbox Code Playgroud)


小智 5

将集合视图的估计大小从自动变为“无”值。

您可以通过故事板或以编程方式完成此操作。

但您必须使用自定义布局类或“UICollectionViewDelegateFlowLayout”协议 API 手动计算它