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

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

    This works for me:

    Invalidate the layout on rotation:

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        collectionView.collectionViewLayout.invalidateLayout()
    }
    

    Have a separate function for calculating the available width:

    Note: taking in to account both section inset and content inset.

    // MARK: - Helpers
    
    func calculateCellWidth(for collectionView: UICollectionView, section: Int) -> CGFloat {
        var width = collectionView.frame.width
        let contentInset = collectionView.contentInset
        width = width - contentInset.left - contentInset.right
    
        // Uncomment the following two lines if you're adjusting section insets
        // let sectionInset = self.collectionView(collectionView, layout: collectionView.collectionViewLayout, insetForSectionAt: section)
        // width = width - sectionInset.left - sectionInset.right
    
        // Uncomment if you are using the sectionInset property on flow layouts
        // let sectionInset = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset ?? UIEdgeInsets.zero
        // width = width - sectionInset.left - sectionInset.right
    
        return width
    }
    

    And then of course finally returning the item size:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: calculateCellWidth(for: collectionView, section: indexPath.section), height: 60)
    }
    

    I think it is important to note that this works because invalidating a layout wont trigger a recalculation of the cell size immediately, but during the next layout update cycle. This means that once the item size callback is eventually called, the collection view has the correct frame, thus allowing accurate sizing.

    Voila!

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

    I found that this worked quite well for UICollectionViewController and animated correctly:

    - (void)viewWillTransitionToSize:(CGSize)size
           withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        // Ensure the layout is within the allowed size before animating below, or 
        //  `UICollectionViewFlowLayoutBreakForInvalidSizes` breakpoint will trigger
        //  and the logging will occur.
    
        if ([self.collectionView.collectionViewLayout isKindOfClass:[YourLayoutSubclass class]]) {
            [(YourLayoutSubclass *)self.collectionView.collectionViewLayout updateForWidth:size.width];
        }
    
        // Then, animate alongside the transition, as you would:
    
        [coordinator animateAlongsideTransition:^
            (id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
                [self.collectionView.collectionViewLayout invalidateLayout];
            }
                                     completion:nil];
    
        [super viewWillTransitionToSize:size
              withTransitionCoordinator:coordinator];
    }
    
    ///////////////
    
    @implementation YourLayoutSubclass
    
    - (void)prepareLayout {
        [super prepareLayout];
    
        [self updateForWidth:self.collectionView.bounds.size.width];
    }
    
    - (void)updateForWidth:(CGFloat)width {
        // Update layout as you wish...
    }
    
    @end
    

    ... See inline code comments above for explanation.

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

    For Xcode 11, none of the above methods worked for me.

    It turned out one need to set the Estimate Size to None in the collection view size panel.

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

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

    You can check in debugger if collectionView.contentOffset is changed to negative in my case it changes from (0,0) to (0,-40). You can solve this issue by using this method

    if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {
       self.automaticallyAdjustsScrollViewInsets = NO;
    }
    
    0 讨论(0)
  • 2020-12-01 02:14

    This is what you need:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        //Get frame width
        let width = self.view.frame.width
        //I want a width of 418 and height of 274 (Aspect ratio 209:137) with a margin of 24 on each side of the cell (See insetForSectionAt 24 + 24 = 48). So, check if a have that much screen real estate.
        if width > (418 + 48) {
            //If I do return the size I want
            return CGSize(width: 418, height: 274)
        }else{
            //Get new width. Frame width minus the margins I want to maintain
            let newWidth = (width - 48)
            //If not calculate the new height that maintains the aspect ratio I want. NewHeight = (originalHeight / originalWidth) * newWidth
            let height = (274 / 418) * newWidth
            //Return the new size that is Aspect ratio 209:137
            return CGSize(width: newWidth, height: height)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 33
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 33
    }
    
    0 讨论(0)
  • 2020-12-01 02:15

    XCode 11

    For me, the reason was that the CollectionView's Estimate option size was set to Automatic. It seems it is the default behavior in XCode 11.

    Hence for me which I loaded the images in the cells, because of the size of the images and the automatic option (which wants to adapt the size of the cell with the size of the image) the cell's width became greater than the CollectionView's width.

    By setting this option to None the problem solved.

    0 讨论(0)
提交回复
热议问题