We successfully created UICollectionView
with dynamic sizing cells.
The initial layout is perfect and the cells look good with no warnings. But when we use reloadData
after selection occurs the UICollectionView
contentOffset
resets to zero.
I have created a demo project showing the issue: https://github.com/SocialKitLtd/selfSizingIssue/
In general, we set up the UICollectionFlowLayout
with UICollectionViewFlowLayout.automaticSize
and set up the constraints within the cell correctly (hence the proper layout).
The only "fix" that we did that works (which is not reliable at all), is to manually setting the contentOffset again after reloading the data.
We don't see a reason for the content reset to occur, feels like we are missing something.
Any help will be highly appreciated!
Video demonstrating the issue:
It looks like you're doing a whole lotta stuff that doesn't need to be (and shouldn't be) done.
Couple examples...
1 - You're overriding intrinsicContentSize
and contentSize
, and calling layout funcs at the same time. But... you have set a size for your collection view via constraints. So, intrinsicContentSize
has no effect, but the funcs you're calling in contentSize
may be causing issues.
2 - You're setting flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
and returning .init(width: 1, height: 1)
for sizeForItemAt
... you should use a reasonable estimated size, and not implement sizeForItemAt
.
3 - There is no need to reloadData()
to update the appearance of the selected cell... Collection Views track the selected cell(s) for us. It's easier to override var isSelected: Bool
in the cell class. Unless...
4 - You are repeatedly calling reloadData()
. When you reloadData()
, you are telling the collection view to de-select any selected cells.
I put up a modification to your repo here: https://github.com/DonMag/CollectionViewSelfSizingIssue
Edit - After comments...
OK - the intrinsicContentSize
implementation is there to allow the collection view to be centered when we have only a few items. That appears to work fine.
The reason the collection is getting "shifted back to the start" on reloadData()
is due to this:
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: 1, height: 1)
}
I'm not an Apple engineer, but as I understand it (and this can be confirmed with some debug print()
statements):
reloadData()
, the collection view calls sizeForItemAt
for every item in the data setif we do this:
items = (0..<150).map { "\($0)" }
sizeForItemAt
will be called 150 times before the first call to cellForItemAt
.
So, if we have 10 items, and we're returning a width of 1
for every cell, the collection view thinks:
10 * 1 == 10
9 * 5 == 45 // 9 5-point inter-item spaces
------------
Total collection view width will be 55-points
And, naturally, it shifts back to starting with cell 0
, because all 10 cells are going to fit.
I've updated my repo to allow both collection views to "center themselves" when there are only a few items.