Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix overlapping items after off-screen updates #69

Merged
merged 1 commit into from
Feb 21, 2020

Conversation

bryankeller
Copy link
Contributor

@bryankeller bryankeller commented Feb 20, 2020

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 for MagazineLayout 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 attributes
immediately 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 to true.
At this time, MagazineLayout has no way of knowing the details of this data source count
change (where the insert/delete/move took place). MagazineLayout only gets this additional
information once prepareForCollectionViewUpdates: is invoked. At that time, we're able to
update our layout's source of truth, the ModelState, which allows us to resolve the
post-batch-update layout and return post-batch-update layout attributes from this function.
Between the time that invalidateLayout: is invoked with invalidateDataSourceCounts set to
true, and when prepareForCollectionViewUpdates: is invoked with details of the updates,
layoutAttributesForElementsInRect: is invoked with the expectation that we already have a
fully 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 this
situation, which works around the bug.
UICollectionViewCompositionalLayout, in classic UIKit fashion, avoids this bug / feature by
implementing the private function
_prepareForCollectionViewUpdates:withDataSourceTranslator:, which provides the layout with
details about the updates to the collection view before layoutAttributesForElementsInRect:
is invoked, enabling them to resolve their layout in time.

Before After
ezgif-6-ee03da57d312 ezgif com-video-to-gif-6
Before After
ezgif com-video-to-gif-8 ezgif com-video-to-gif-9

Related Issue

N/A

Motivation and Context

This works around an old issue that's affected MagazineLayout since day one. Also, I love a good UICollectionView bug.

How Has This Been Tested

  • Tested in sample project
  • Tested in Airbnb app

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.

@bryankeller bryankeller added the bug Something isn't working label Feb 20, 2020
@bryankeller bryankeller force-pushed the bk/prevent-overlapping-items-after-updates branch from f91050b to b44e6cc Compare February 20, 2020 06:15
@bryankeller bryankeller force-pushed the bk/prevent-overlapping-items-after-updates branch from b44e6cc to df385ed Compare February 20, 2020 22:42
Copy link

@brynbodayle brynbodayle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff, thanks for fixing this!

@bryankeller bryankeller merged commit bbbe145 into master Feb 21, 2020
@bryankeller bryankeller deleted the bk/prevent-overlapping-items-after-updates branch February 21, 2020 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants