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.
There is a property on
UIViewController
–automaticallyAdjustsScrollViewInsets
–that defaults toYES
. This means that when aUIViewController
has aUIScrollView
in its view hierarchy–which is true of aUICollectionViewController
–thecontentInset
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:
The solution is to set
automaticallyAdjustsScrollViewInsets
toNO
somewhere in yourUICollectionViewController
subclass, such as inviewDidLoad
:I have put an example project on GitHub that illustrates this problem and solution. There are two branches:
with_error
andfixed_error
. Here is a diff of the change on GitHub.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:ios 10: topmost view was not connected to the view outlet
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!
iOS 11 update:
automaticallyAdjustsScrollViewInsets
is deprecated in iOS 11.0.Apple recommends using
UIScrollView
'scontentInsetAdjustmentBehavior
method instead. I set this value to.never
and the error has gone. You can also set this property in Interface Builder.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 insizeForItemAt:indexPath:
.