Why does UICollectionView log an error when the ce

2020-02-02 10:56发布

I have a UICollectionViewController using a UICollectionViewFlowLayout where my itemSize is the size of the UICollectionView. Basically, this is a line layout of cells where each cell is fullscreen and scrolls horizontally.

In my UICollectionViewFlowLayout subclass, I have overridden prepareLayout as follows:

- (void)prepareLayout {
    self.itemSize = self.collectionView.frame.size;
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.collectionView.pagingEnabled = YES;
    self.minimumLineSpacing = 0.0;
    self.minimumInteritemSpacing = 0.0;
    self.sectionInset = UIEdgeInsetsZero;
    self.footerReferenceSize = CGSizeZero;
    self.headerReferenceSize = CGSizeZero;
}

The UICollectionViewController is very basic returning 10 items in one section. I've included a sample project on GitHub for more detail.

Everything appears to be set up correctly. It looks right in the simulator and on the device but, when the collection view is displayed, there is an error logged to the console:

the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less that the height of the UICollectionView minus the section insets top and bottom values.

Note also that the collection view controller in my example is in a navigation controller and while that doesn't look particularly necessary in the example, in my real-world case I need the collection view in a navigation controller.

8条回答
地球回转人心会变
2楼-- · 2020-02-02 11:31

There is a property on UIViewControllerautomaticallyAdjustsScrollViewInsets–that defaults to YES. This means that when a UIViewController has a UIScrollView in its view hierarchy–which is true of a UICollectionViewController–the contentInset property of that scroll view is adjusted automatically to account for screen areas consumed by the status bar, navigation bar, and toolbar or tab bar.

The documentation for that property states:

automaticallyAdjustsScrollViewInsets

Specifies whether or not the view controller should automatically adjust its scroll view insets.

@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets

Discussion

Default value is YES, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to NO if you want to manage scroll view inset adjustments yourself, such as when there is more than one scroll view in the view hierarchy.

The solution is to set automaticallyAdjustsScrollViewInsets to NO somewhere in your UICollectionViewController subclass, such as in viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.automaticallyAdjustsScrollViewInsets = NO;
}

I have put an example project on GitHub that illustrates this problem and solution. There are two branches: with_error and fixed_error. Here is a diff of the change on GitHub.

查看更多
时光不老,我们不散
3楼-- · 2020-02-02 11:33

I encountered this problem when rotating the device from portrait to landscape, back to portrait. You want to invalidate the collectionView's layout upon device rotation and before the call to super, like so:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    // Causes collection view cells to be resized upon orientation change.
    // Important that this is called *before* call to super in order to prevent error from being logged to console.
    [self.collectionView.collectionViewLayout invalidateLayout];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    //...
}
查看更多
放荡不羁爱自由
4楼-- · 2020-02-02 11:36

ios 10: topmost view was not connected to the view outlet

查看更多
Lonely孤独者°
5楼-- · 2020-02-02 11:38

This way had worked for me perfectly!.

I just subtracted the top and bottom insets from the view's height as said in that error.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: view.frame.width , height: view.frame.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom)) }

I hope it helps!

查看更多
Lonely孤独者°
6楼-- · 2020-02-02 11:39

iOS 11 update: automaticallyAdjustsScrollViewInsets is deprecated in iOS 11.0.

Apple recommends using UIScrollView's contentInsetAdjustmentBehavior method instead. I set this value to .never and the error has gone. You can also set this property in Interface Builder.

查看更多
放荡不羁爱自由
7楼-- · 2020-02-02 11:45

This issue just occured to me on 3x screens (namely the iPhone 6 Plus.) As it turned out, the autolayout engine did not really like infinite floating point values (such as .33333333), so my solution was to floor the return height in sizeForItemAt:indexPath:.

return CGSize(width: preferredWidth, height: floor(preferredHeight))
查看更多
登录 后发表回答