Fix overlapping items after off-screen updates #69
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Details
This PR fixes an issue that causes off-screen batch updates to sometimes cause visual defects in the form of temporary overlapping items. It's probably a
UICollectionView
bug, but thankfully, there's a way forMagazineLayout
to work around it. Here's the technical description straight from the in-code documentation:This prevents an issue that causes overlapping / misplaced elements after an
off-screen batch update occurs. The root cause of this issue is that
UICollectionView
expects
layoutAttributesForElementsInRect:
to return post-batch-update layout attributesimmediately after an update is sent to the collection view via the insert/delete/reload/move
functions. Unfortunately, this is impossible - when batch updates occur,
invalidateLayout:
is invoked immediately with a context that has
invalidateDataSourceCounts
set totrue
.At this time,
MagazineLayout
has no way of knowing the details of this data source countchange (where the insert/delete/move took place).
MagazineLayout
only gets this additionalinformation once
prepareForCollectionViewUpdates:
is invoked. At that time, we're able toupdate our layout's source of truth, the
ModelState
, which allows us to resolve thepost-batch-update layout and return post-batch-update layout attributes from this function.
Between the time that
invalidateLayout:
is invoked withinvalidateDataSourceCounts
set totrue
, and whenprepareForCollectionViewUpdates:
is invoked with details of the updates,layoutAttributesForElementsInRect:
is invoked with the expectation that we already have afully resolved layout. If we return incorrect layout attributes at that time, then we'll have
overlapping elements / visual defects. To prevent this, we can return
nil
in thissituation, which works around the bug.
UICollectionViewCompositionalLayout
, in classic UIKit fashion, avoids this bug / feature byimplementing the private function
_prepareForCollectionViewUpdates:withDataSourceTranslator:
, which provides the layout withdetails about the updates to the collection view before
layoutAttributesForElementsInRect:
is invoked, enabling them to resolve their layout in time.
Related Issue
N/A
Motivation and Context
This works around an old issue that's affected
MagazineLayout
since day one. Also, I love a goodUICollectionView
bug.How Has This Been Tested
Types of changes
Checklist