-
Notifications
You must be signed in to change notification settings - Fork 33
Adding a programmatic scroll completion handler #582
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
Adding a programmatic scroll completion handler #582
Conversation
Adding the completion handler to ListActions.
|
I've pushed up a change to add the completion handler to the equivalent |
Adding tests for queued handlers.
Adding a scroll test for a floating point offset.
| /// This function will determine if a call to `collectionView.scrollToItem(...)` | ||
| /// will result in an adjusted content offset. This is necessary because when the | ||
| /// item is already at the expected position, `UICollectionView` will not scroll | ||
| /// and will not execute its `scrollViewDidEndScrollingAnimation(_:)` delegate. | ||
| func willScroll( | ||
| for scrollPosition: UICollectionView.ScrollPosition, | ||
| itemFrame: CGRect, | ||
| viewport: CGRect, | ||
| contentSize: CGSize | ||
| ) -> Bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just thinking through what it would mean if the scroll view behavior ever changed slightly and introduced a mismatch:
- We return
falsebut the scroll view does actually scroll- Completion will fire early
- We return
truebut the scroll view doesn't actually scroll- Completion won't fire at all (right?) (edit: or would potentially fire on some other scroll event later on?)
Do you figure the risk of this getting out of sync is pretty low?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, you're right on both cases. For the case where true is returned but the scroll view doesn't actually scroll, we would end up running the handler after the next call to scrollTo(...) runs.
UICollectionView won't animate when the distance to scroll is under 0.5 points. To future proof this function, we can floor/ceil each of these measurements so that they must be greater than or equal to 1.0 points when calculating both the distance to scroll and whether the collection view can move in a particular direction.
This will result in the completion handler running before the collection view moves in some cases where the distance is under 1.0 points, but I think this is fine. This should reduce risks related to slight changes in UIKit's implementation.
Here's a commit with the update: c1659c8. I can take this in a different direction if there are any concerns!
g-mark
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
| } else { | ||
| // Dispatch so that scrolling without an animation executes the closure | ||
| // on the next runloop execution, similar to scrolling with an animation. | ||
| DispatchQueue.main.async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we ever have a non-animated handleScrollCompletion when scrollCompletionHandlers isn't empty? I'm not sure it would really matter, but curious if this came up at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for raising this question. This shouldn't be possible because right before handleScrollCompletion(...) is executed with .scrolled(false) as the reason, the collection view's offset will have just been adjusted without an animation. This offset adjustment cancels any ongoing scroll animation and empties the scrollCompletionHandlers.
Adding a guard statement to didEndScrolling and improving docs.
4f2398e to
e35c751
Compare
* main: Adding a programmatic scroll completion handler (#582)
This builds on the changes in #582, adding a completion handler to the `scrollToSection(...)` API. This also adds a demo to showcase this API with various configurations: <img width="300" alt="Screenshot 2025-06-30 at 4 33 33 PM" src="https://github.com/user-attachments/assets/03f04302-ead2-4bba-b773-ce096106adba" />
…-headerfooters * origin/main: build: set up tuist (#584) Bumping versions to 16.3.0 (#589) Reset scroll position if list identifier changes (#588) Bumping versions to 16.2.0 (#587) Adding a completion handler to the `scrollToSection` API. (#585) Adding a programmatic scroll completion handler (#582) Remove iOS 19 (26) cap of the collection view first responder workaround (#581) Bumping versions to 16.1.0 (#583) Update for Blueprint 6.0.0 (#580) Bumping versions to 16.0.4. (#579) Update the first responder resignation workaround to be enabled by default and cap at < iOS 19 [UI-8849] (#578) Bumping versions to 16.0.3 (#577) Bottom gravity and autoscroll improvements (#576) Bumping versions to 16.0.2 (#574) Addressing an AutoScrollAction issue when using VerticalLayoutGravity.bottom (#572) release: Prepare 16.0.1 release (#569) Fix reordering crash introduced in 16.0 (#568)
This PR adds a completion handler to the
scrollTo(item:position:animated:)API, turning it intoscrollTo(item:position:animated:completion:).This also adds unit tests to assert the expected items are visible in the completion callback. A new demo allows you to use this API in a number of layout contexts, leveraging console logs when the scroll completion handler is executed:

Checklist
Please do the following before merging:
Mainsection.