Same code like this
collectionLayout.estimatedItemSize = CGSize(width: 50, height: 25)
collectionLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize
collectionLayout.minimumInteritemSpacing = 10
for _ in 0 ..< 1000 {
let length = Int(arc4random() % 8)
let string = randomKeyByBitLength(length)
array.append(string!)
}
collectionView.reloadData()
cell constraints:
when I run it on iOS 12, it's different. left simulator is iOS 11, and right is iOS 12:
But, when I scroll it, cells's frames will be normal.
Sample project to reproduce the issue: https://github.com/Coeur/StackOverflow51375566
For all solutions, note that there is no need to explicitly call
reloadData
inviewDidLoad
: it will happen automatically.Solution 1
Inspired by Samantha idea:
invalidateLayout
asynchronously inviewDidLoad
.Solution 2
(imperfect, see DHennessy13 improvement on it)
Based on Peter Lapisu answer.
invalidateLayout
inviewWillLayoutSubviews
.As noted by DHennessy13, this current solution with
viewWillLayoutSubviews
is imperfect as it will invalidateLayout when rotating the screen.You may follow DHennessy13 improvement regarding this solution.
Solution 3
Based on a combination of Tyler Sheaffer answer, Shawn Aukstak port to Swift and Samantha idea. Subclass your CollectionView to perform
invalidateLayout
onlayoutSubviews
.This solution is elegant as it doesn't require to change your ViewController code. I've implemented it on branch AutoLayoutCollectionView of this sample project https://github.com/Coeur/StackOverflow51375566/tree/AutoLayoutCollectionView.
Solution 4
Rewrite UICollectionViewCell default constraints. See Larry answer.
Solution 5
Implement
collectionView(_:layout:sizeForItemAt:)
and returncell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
. See matt answer.Here's another solution that works on Cœur's code sample, and also worked for my particular case, where the other answers didn't. The code below replaces the previous implementation of the
CollectionViewCell
subclass inViewController.swift
:This is inspired by the answer by ale84 from UICollectionViewFlowLayout estimatedItemSize does not work properly with iOS12 though it works fine with iOS 11.*
We had the same problem on our project. We also noticed differences between the multiple devices in iOS 12, requiring a call to
layoutIfNeeded
&invalidateLayout
. The solution is based on @DHennessy13 's approach but doesn't require a boolean to manage states that seemed slightly hacky.Here it is based on an Rx code, basically the first line is when the data is changing, inside the
subscribe
is what needs to be done to fix the nasty iOS 12 UI glitch:Edit:
By the way, it seems to be a known issue in iOS 12: https://developer.apple.com/documentation/ios_release_notes/ios_12_release_notes (in UIKit section).
I have the same problem, cells use the estimated size (instead of automatic size) until scrolled. The same code built with Xcode 9.x runs perfectly fine on iOS 11 and 12, and built in Xcode 10 it runs correctly on iOS 11 but not iOS 12.
The only way I’ve found so far to fix this is to invalidate the collection view’s layout either in
viewDidAppear
, which can cause some jumpiness, or in an async block insideviewWillAppear
(not sure how reliable that solution is).Try this
Adding to
viewDidAppear
andviewWillAppear
will of course work. ButviewDidAppear
will cause a glitch gor the user.Solution 2 of Cœur's prevents the layout from flashing or updating in front of the user. But it can create problems when you rotate the device. I'm using a variable "shouldInvalidateLayout" in viewWillLayoutSubviews and setting it to false in viewDidAppear.