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

后端 未结 20 2156
温柔的废话
温柔的废话 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:16

    I could solve it by putting super.prepare() at end of override func prepare() { }

    0 讨论(0)
  • 2020-12-01 02:17

    Turn your collection view's estimate size 'None' value from automatic.

    You can do this by the storyboard or programatically.

    But you have to calculate it manually with custom layout class or 'UICollectionViewDelegateFlowLayout' protocol APIs

    0 讨论(0)
  • 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
    0 讨论(0)
  • 2020-12-01 02:18

    Its happens because your collection view cell's width is bigger than collection view width after rotation.suppose that you have a 1024x768 screen and your collection view fills the screen.When your device is landscape,your cell's width will be self.collectionView.frame.size.width - 20 =1004 and its greater than your collection view's width in portrait = 768.The debugger says that "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".

    0 讨论(0)
  • 2020-12-01 02:21

    This happens when your collection view resizes to something less wide (go from landscape to portrait mode, for example), and the cell becomes too large to fit.

    Why is the cell becoming too large, as the collection view flow layout should be called and return a suitable size ?

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

    Update to include Swift 4

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

    This is because this function is not called, or at least not straight away.

    What happens is that your collection view flow layout subclass does not override the shouldInvalidateLayoutForBoundsChange function, which returns false by default.

    When this method returns false, the collection view first tries to go with the current cell size, detects a problem (which logs the warning) and then calls the flow layout to resize the cell.

    This means 2 things :

    1 - The warning in itself is not harmful

    2 - You can get rid of it by simply overriding the shouldInvalidateLayoutForBoundsChange function to return true. In that case, the flow layout will always be called when the collection view bounds change.

    0 讨论(0)
  • 2020-12-01 02:21

    I've solve this problem by using safeAreaLayoutGuide.

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
        return CGSize(width: (view.safeAreaLayoutGuide.layoutFrame.width), height: 80);
    }
    

    and you also have to override this function to support portrait and landscape mode correctly.

     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        collectionView?.collectionViewLayout.invalidateLayout();
    }
    
    0 讨论(0)
提交回复
热议问题