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
This commit is contained in:
Antti Moilanen 2016-09-26 16:01:07 -07:00 committed by Facebook Github Bot 7
parent 0ce2bbdd64
commit 72e203bf95

View File

@ -381,6 +381,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
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 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
// 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