From deef8aade288f2afa83de96947a851d45391915f Mon Sep 17 00:00:00 2001 From: Adam Comella Date: Fri, 6 May 2016 03:18:20 -0700 Subject: [PATCH] ScrollView: Always fire onScroll event for the resting scroll position Summary: When throttling scroll events with `scrollEventThrottle`, `onScroll` is not guaranteed to be fired for the final scroll position of the `ScrollView`. This can cause a component to render UI that is consistent with the resting scroll position of the `ScrollView`. This commit guarantees that an `onScroll` event will be fired for the resting scroll position of the `ScrollView`. **Test plan (required)** Verified commit fixes a reduced repro. Also tested fix in a larger app. Adam Comella Microsoft Corp. Closes https://github.com/facebook/react-native/pull/7366 Differential Revision: D3269303 Pulled By: javache fb-gh-sync-id: f68ecb7e9c18d1ac255c6f872fb7eb4aadd07799 fbshipit-source-id: f68ecb7e9c18d1ac255c6f872fb7eb4aadd07799 --- React/Views/RCTScrollView.m | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index 452554dd1fe..85e8ede5cb2 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -399,7 +399,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _lastClippedToRect = CGRectNull; _scrollEventThrottle = 0.0; - _lastScrollDispatchTime = CACurrentMediaTime(); + _lastScrollDispatchTime = 0; _cachedChildFrames = [NSMutableArray new]; [self addSubview:_scrollView]; @@ -544,6 +544,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated { if (!CGPointEqualToPoint(_scrollView.contentOffset, offset)) { + // Ensure at least one scroll event will fire + _allowNextScrollNoMatterWhat = YES; [_scrollView setContentOffset:offset animated:animated]; } } @@ -579,9 +581,7 @@ if ([_nativeScrollDelegate respondsToSelector:_cmd]) { \ RCT_FORWARD_SCROLL_EVENT(delegateMethod:scrollView); \ } -RCT_SCROLL_EVENT_HANDLER(scrollViewDidEndScrollingAnimation, onMomentumScrollEnd) //TODO: shouldn't this be onScrollAnimationEnd? RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin) -RCT_SCROLL_EVENT_HANDLER(scrollViewDidEndDecelerating, onMomentumScrollEnd) RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll) - (void)scrollViewDidScroll:(UIScrollView *)scrollView @@ -725,6 +725,28 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll) RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndZooming:scrollView withView:view atScale:scale); } +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView +{ + // Fire a final scroll event + _allowNextScrollNoMatterWhat = YES; + [self scrollViewDidScroll:scrollView]; + + // Fire the end deceleration event + RCT_SEND_SCROLL_EVENT(onMomentumScrollEnd, nil); + RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndDecelerating:scrollView); +} + +- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView +{ + // Fire a final scroll event + _allowNextScrollNoMatterWhat = YES; + [self scrollViewDidScroll:scrollView]; + + // Fire the end deceleration event + RCT_SEND_SCROLL_EVENT(onMomentumScrollEnd, nil); //TODO: shouldn't this be onScrollAnimationEnd? + RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndScrollingAnimation:scrollView); +} + - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { if ([_nativeScrollDelegate respondsToSelector:_cmd]) {