the behavior of the UICollectionViewFlowLayout is not defined, because the cell width is greater than collectionView width

后端 未结 20 2235
温柔的废话
温柔的废话 2020-12-01 01:53

2015-08-18 16:07:51.523 Example[16070:269647] the behavior of the UICollectionViewFlowLayout is not defined because: 2015-08-18 16:07:51.523
Example

20条回答
  •  时光说笑
    2020-12-01 02:18

    I am using a subclass of UICollectionViewFlowLayout and using its itemSize property to specify the cell size (instead of the collectionView:sizeForItemAtIndexPath: delegate method). Every time I rotate the screen to a shorter width one (e.g. landscape -> portrait) I get this huge warning in question.

    I was able to fix it by doing 2 steps.

    Step 1: In UICollectionViewFlowLayout subclass's prepareLayout() function, move super.prepareLayout() to after where self.itemSize is set. I think this makes the super class to use the correct itemSize value.

    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()
      }
    
      // ...
    
    }
    

    Note that the above change will somehow make the layout size change when screen rotates stops working. This is where step 2 comes in.

    Step 2: Put this in the view controller that holds the collection view.

      override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        collectionView.collectionViewLayout.invalidateLayout()
      }
    

    Now the warning is gone :)


    Some Notes:

    1. Make sure you are adding constraints to the collectionView and not using collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    2. Make sure you are not calling invalidateLayout in viewWillTransitionToSize() because the width of an edge-to-edge cell in landscape is larger than the collection view’s frame width in portrait. See below references.

    References

    • Making Adaptive Forms using UICollectionView
    • Collection view with self-sizing cells

提交回复
热议问题