From 72e203bf9572f2dbd6e836f35db3afdfdba3d6c4 Mon Sep 17 00:00:00 2001 From: Antti Moilanen Date: Mon, 26 Sep 2016 16:01:07 -0700 Subject: [PATCH] Fix ScrollView's snap index when scrolling forward and user taps the screen again while still scrolling Summary: Currently when snapping is used with ScrollView it calculates wrong snap index if user taps the screen second time while ScrollView is still scrolling. This happens because the code only adds 1 to the snap index when translationAlongAxis is smaller than zero. When user taps screen second time the translationAlongAxis is 0 and snap index ends up being one less than it should. This causes the ScrollView to scroll one step backwards. Bug can be reproduced with the new examples I added to UIExplorer's ScrollView in [scrollview-snap-bug-example branch](https://github.com/anttimo/react-native/tree/scrollview-snap-bug-example). Fix can be verified by running the same examples with the ScrollView fix in [scrollview-snap-bug-example-with-fix branch](https://github.com/anttimo/react-native/tree/scrollview-snap-bug-example-with-fix). ![scrollview-bug](https://cloud.githubusercontent.com/assets/150881/14427555/10d59d1e-fffe-11 Closes https://github.com/facebook/react-native/pull/6906 Differential Revision: D3927123 Pulled By: majak fbshipit-source-id: 38828cc60a02a754bdc3ec72fb98d8777917f15e --- React/Views/RCTScrollView.m | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index 1f0de277630a7a..f36dc4eeac4445 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -381,6 +381,10 @@ @implementation RCTScrollView uint16_t _coalescingKey; NSString *_lastEmittedEventName; NSHashTable *_scrollListeners; + // The last non-zero value of translationAlongAxis from scrollViewWillEndDragging. + // Tells if user was scrolling forward or backward and is used to determine a correct + // snap index when the user stops scrolling with a tap on the scroll view. + CGFloat _lastNonZeroTranslationAlongAxis; } - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher @@ -699,7 +703,14 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi // Pick snap point based on direction and proximity NSInteger snapIndex = floor((targetContentOffsetAlongAxis + alignmentOffset) / snapToIntervalF); - snapIndex = (translationAlongAxis < 0) ? snapIndex + 1 : snapIndex; + BOOL isScrollingForward = translationAlongAxis < 0; + BOOL wasScrollingForward = translationAlongAxis == 0 && _lastNonZeroTranslationAlongAxis < 0; + if (isScrollingForward || wasScrollingForward) { + snapIndex = snapIndex + 1; + } + if (translationAlongAxis != 0) { + _lastNonZeroTranslationAlongAxis = translationAlongAxis; + } CGFloat newTargetContentOffset = ( snapIndex * snapToIntervalF ) - alignmentOffset; // Set new targetContentOffset