From 6237cfb325e39571ede0054a67d60f2c978d6d58 Mon Sep 17 00:00:00 2001 From: Nikita Shanin Date: Sun, 26 Jan 2020 19:08:04 -0800 Subject: [PATCH] disable momentum scrolling for vertical ScrollView (#27666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Following up changes added in https://github.com/facebook/react-native/issues/24045 I had the same use case for vertical ScrollView. This PR just enables existing `disableIntervalMomentum` property to work with vertical ScrollViews: restricts vertical pagination when page height is less than height of ScrollView. ## Changelog [General] [Changed] - changed property `disableIntervalMomentum` to work with both horizontal and vertical ScrollViews Pull Request resolved: https://github.com/facebook/react-native/pull/27666 Test Plan: No new tests at the moment `iOS` ``` All tests Test Suite RNTesterUnitTests.xctest started RCTAllocationTests ✓ testBridgeIsDeallocated (0.045 seconds) ✓ testContentViewIsInvalidated (0.006 seconds) ✓ testModuleMethodsAreDeallocated (0.002 seconds) ✓ testModulesAreDeallocated (0.022 seconds) ✓ testModulesAreInvalidated (0.017 seconds) RCTAnimationUtilsTests ✓ testClampExtrapolate (0.002 seconds) ✓ testExtendExtrapolate (0.002 seconds) ✓ testIdentityExtrapolate (0.001 seconds) ✓ testManySegments (0.003 seconds) ✓ testSimpleOneToOneMapping (0.002 seconds) ✓ testWiderInputRange (0.003 seconds) ✓ testWiderOutputRange (0.002 seconds) RCTBlobManagerTests ✓ testCreateFromParts (0.002 seconds) ✓ testRemove (0.001 seconds) ✓ testResolve (0.001 seconds) ✓ testResolveMap (0.001 seconds) ✓ testResolveURL (0.001 seconds) RCTBundleURLProviderTests ✓ testBundleURL (0.041 seconds) ✓ testIPURL (0.005 seconds) ✓ testLocalhostURL (0.005 seconds) RCTComponentPropsTests ✓ testNeedsOffscreenAlphaCompositing (0.019 seconds) ✓ testResetBackgroundColor (0.008 seconds) ✓ testResetProps (0.012 seconds) ✓ testSetProps (0.009 seconds) RCTConvert_NSURLTests ✓ test_basic (0.002 seconds) ✓ test_documentsFolder (0.001 seconds) ✓ test_filePath (0.001 seconds) ✓ test_filePathWithEncodedSpaces (0.001 seconds) ✓ test_filePathWithSpaces (0.001 seconds) ✓ test_fileURL (0.001 seconds) ✓ test_fullURL (0.001 seconds) ✓ test_imageAt2XPath (0.001 seconds) ✓ test_imageFile (0.001 seconds) ✓ test_imageURL (0.001 seconds) ✓ test_imageURLWithSpaces (0.001 seconds) ✓ test_null (0.001 seconds) ✓ test_unicodeURL (0.001 seconds) ✓ test_urlWithEncodedSpaces (0.001 seconds) ✓ test_urlWithSpaces (0.001 seconds) ✓ testDataURL (0.003 seconds) RCTConvert_YGValueTests ✓ testNumberPoints (0.002 seconds) ✓ testStringPercent (0.002 seconds) ✓ testUndefined (0.001 seconds) RCTDevMenuTests ✓ testClosingActionSheetAfterAction (0.009 seconds) ✓ testShowCreatingActionSheet (0.017 seconds) RCTEventDispatcherTests ✓ testBasicCoalescingReturnsLastEvent (0.006 seconds) ✓ testCoalescingEventIsImmediatelyDispatched (0.001 seconds) ✓ testDifferentEventTypesDontCoalesce (0.001 seconds) ✓ testDifferentViewTagsDontCoalesce (0.001 seconds) ✓ testLegacyEventsAreImmediatelyDispatched (0.001 seconds) ✓ testMultipleEventsResultInOnlyOneDispatchAfterTheFirstOne (0.001 seconds) ✓ testNonCoalescingEventIsImmediatelyDispatched (0.001 seconds) ✓ testRunningTheDispatchedBlockResultInANewOneBeingEnqueued (0.001 seconds) ✓ testSameEventTypesWithDifferentCoalesceKeysDontCoalesce (0.001 seconds) RCTFontTests ✓ testFamily (0.029 seconds) ✓ testFamilyAndStyle (0.001 seconds) ✓ testFamilyAndWeight (0.002 seconds) ✓ testFamilyStyleAndWeight (0.002 seconds) ✓ testInvalidFont (0.002 seconds) ✓ testSize (0.001 seconds) ✓ testStyle (0.003 seconds) ✓ testStyleAndWeight (0.002 seconds) ✓ testVariant (0.002 seconds) ✓ testWeight (0.002 seconds) RCTFormatErrorTests ✓ testSymbolication (0.002 seconds) RCTGzipTests ✓ testDontRezipZippedData (0.004 seconds) ✓ testGzip (0.002 seconds) ✓ testRequestBodyEncoding (0.003 seconds) RCTImageLoaderTests ✓ testImageDecoding (0.010 seconds) ✓ testImageLoaderUsesImageDecoderWithHighestPriority (0.003 seconds) ✓ testImageLoaderUsesImageURLLoaderWithHighestPriority (0.004 seconds) ✓ testImageLoading (0.004 seconds) RCTImageUtilTests ✓ testLandscapeSourceLandscapeTarget (0.001 seconds) ✓ testPortraitSourceLandscapeTarget (0.001 seconds) ✓ testPortraitSourcePortraitTarget (0.001 seconds) ✓ testRounding (0.001 seconds) ✓ testScaling (0.001 seconds) RCTJSONTests ✓ testDecodingArray (0.001 seconds) ✓ testDecodingMutableArray (0.001 seconds) ✓ testDecodingObject (0.001 seconds) ✓ testDecodingString (0.001 seconds) ✓ testEncodingArray (0.001 seconds) ✓ testEncodingNSError (0.023 seconds) ✓ testEncodingObject (0.001 seconds) ✓ testEncodingString (0.001 seconds) ✓ testErrorPointer (0.002 seconds) ✓ testLeadingWhitespace (0.001 seconds) ✓ testNaN (0.001 seconds) ✓ testNotJSONSerializable (0.001 seconds) ✓ testNotUTF8Convertible (0.004 seconds) RCTMethodArgumentTests ✓ testAttributes (0.001 seconds) ✓ testGenericArray (0.001 seconds) ✓ testGenericDictionary (0.001 seconds) ✓ testGenericSet (0.001 seconds) ✓ testNamespacedCxxStruct (0.001 seconds) ✓ testNestedGenericArray (0.001 seconds) ✓ testNewlines (0.001 seconds) ✓ testNullability (0.001 seconds) ✓ testOneArgument (0.001 seconds) ✓ testSemicolonStripping (0.001 seconds) ✓ testSpaces (0.001 seconds) ✓ testTwoArguments (0.001 seconds) ✓ testUnnamedArgs (0.001 seconds) ✓ testUntypedUnnamedArgs (0.001 seconds) ✓ testUnused (0.001 seconds) RCTModuleInitNotificationRaceTests ✓ testViewManagerNotInitializedBeforeSetBridgeModule (0.009 seconds) RCTModuleInitTests ✓ testCustomInitModuleInitializedAtBridgeStartup (0.005 seconds) ✓ testCustomSetBridgeModuleInitializedAtBridgeStartup (0.006 seconds) ✓ testExportConstantsModuleInitializedAtBridgeStartup (0.005 seconds) ✓ testInjectedModulesInitializedDuringBridgeInit (0.003 seconds) ✓ testLazyInitModuleNotInitializedDuringBridgeInit (0.005 seconds) RCTModuleMethodTests ✓ testFunctionType (0.001 seconds) ✓ testNonnull (0.001 seconds) ✓ testNumbersNonnull (0.001 seconds) ✓ testReturnsNilForDefaultFunction (0.001 seconds) ✓ testReturnsValueForSyncFunction (0.001 seconds) ✓ testReturnTypeForSyncFunction (0.001 seconds) ✓ testStructArgument (0.001 seconds) ✓ testWhitespaceTolerance (0.001 seconds) RCTMultipartStreamReaderTests ✓ testMultipleParts (0.001 seconds) ✓ testNoCloseDelimiter (0.001 seconds) ✓ testNoDelimiter (0.001 seconds) ✓ testSimpleCase (0.001 seconds) RCTNativeAnimatedNodesManagerTests ✓ testAdditionNode (0.002 seconds) ✓ testAnimationCallbackFinish (0.001 seconds) ✓ testCritcallyDampedSpringAnimation (0.003 seconds) ✓ testDecayAnimation (0.004 seconds) ✓ testDecayAnimationLoop (0.012 seconds) ✓ testFramesAnimation (0.001 seconds) ✓ testFramesAnimationLoop (0.002 seconds) ✓ testHandleStoppingAnimation (0.002 seconds) ✓ testInterpolationNode (0.002 seconds) ✓ testMultiplicationNode (0.001 seconds) ✓ testNativeAnimatedEventDoNotUpdate (0.001 seconds) ✓ testNativeAnimatedEventDoUpdate (0.002 seconds) ✓ testNodeValueListenerIfListening (0.001 seconds) ✓ testNodeValueListenerIfNotListening (0.001 seconds) ✓ testSpringAnimationLoop (0.007 seconds) ✓ testSpringTrackingRetainsSpeed (0.007 seconds) ✓ testTracking (0.002 seconds) ✓ testTrackingPausesWhenEndValueIsReached (0.001 seconds) ✓ testUnderdampedSpringAnimation (0.003 seconds) ✓ testViewReceiveUpdatesIfOneOfAnimationHasntStarted (0.001 seconds) ✓ testViewReceiveUpdatesWhenOneOfAnimationHasFinished (0.001 seconds) RCTPerformanceLoggerTests ✓ testLabelCountInSyncWithRCTPLTag (0.001 seconds) RCTShadowViewTests ✓ testAncestorCheck (0.001 seconds) ✓ testApplyingLayoutRecursivelyToShadowView (0.002 seconds) ✓ testAssignsSuggestedHeightDimension (0.001 seconds) ✓ testAssignsSuggestedWidthDimension (0.001 seconds) ✓ testDoesNotAssignSuggestedDimensionsWhenStyledWithFlexAttribute (0.001 seconds) ✓ testDoesNotOverrideDimensionStyleWithSuggestedDimensions (0.001 seconds) RCTUIManagerTests ✓ testManagingChildrenToAddRemoveAndMove (0.001 seconds) ✓ testManagingChildrenToAddViews (0.001 seconds) ✓ testManagingChildrenToRemoveViews (0.001 seconds) RCTURLUtilsTests ✓ testAppendParam (0.001 seconds) ✓ testDuplicateParamTakesLatter (0.001 seconds) ✓ testGetEncodedParam (0.001 seconds) ✓ testGetQueryParam (0.001 seconds) ✓ testIsLocalAssetsURLParam (0.001 seconds) ✓ testNilURLAppendQueryParam (0.001 seconds) ✓ testNilURLGetQueryParam (0.001 seconds) ✓ testQueryParamNotFound (0.001 seconds) ✓ testRemoveParam (0.001 seconds) ✓ testReplaceEncodedParam (0.001 seconds) ✓ testReplaceParam (0.001 seconds) RCTUnicodeDecodeTests ✓ testEmojis (0.001 seconds) ✓ testNiqqud (0.001 seconds) Executed 167 tests, with 0 failures (0 unexpected) in 0.530 (0.667) seconds ``` `Android` ``` PASS 8.4s 7 Passed 0 Skipped 0 Failed com.facebook.react.animated.NativeAnimatedInterpolationTest PASS 16.7s 23 Passed 0 Skipped 0 Failed com.facebook.react.animated.NativeAnimatedNodeTraversalTest PASS 13.5s 4 Passed 0 Skipped 0 Failed com.facebook.react.bridge.BaseJavaModuleTest PASS 341ms 4 Passed 0 Skipped 0 Failed com.facebook.react.bridge.FallbackJSBundleLoaderTest PASS <100ms 1 Passed 0 Skipped 0 Failed com.facebook.react.bridge.JavaOnlyArrayTest PASS 13.0s 10 Passed 0 Skipped 0 Failed com.facebook.react.devsupport.JSDebuggerWebSocketClientTest PASS 6.3s 4 Passed 0 Skipped 0 Failed com.facebook.react.devsupport.MultipartStreamReaderTest PASS 6.1s 5 Passed 0 Skipped 0 Failed com.facebook.react.devsupport.StackTraceHelperTest PASS 13.9s 6 Passed 0 Skipped 0 Failed com.facebook.react.modules.blob.BlobModuleTest PASS 6.7s 5 Passed 0 Skipped 0 Failed com.facebook.react.modules.camera.ImageStoreManagerTest PASS 5.2s 1 Passed 0 Skipped 0 Failed com.facebook.react.modules.clipboard.ClipboardModuleTest PASS 3.8s 5 Passed 0 Skipped 0 Failed com.facebook.react.modules.dialog.DialogModuleTest PASS <100ms 10 Passed 0 Skipped 0 Failed com.facebook.react.modules.network.HeaderUtilTest PASS 3.3s 14 Passed 0 Skipped 0 Failed com.facebook.react.modules.network.NetworkingModuleTest PASS 1.4s 9 Passed 0 Skipped 0 Failed com.facebook.react.modules.network.ProgressiveStringDecoderTest PASS 1.6s 4 Passed 0 Skipped 0 Failed com.facebook.react.modules.network.ReactCookieJarContainerTest PASS 2.2s 2 Passed 0 Skipped 0 Failed com.facebook.react.modules.share.ShareModuleTest PASS 5.1s 6 Passed 0 Skipped 0 Failed com.facebook.react.modules.storage.AsyncStorageModuleTest PASS 2.7s 9 Passed 0 Skipped 0 Failed com.facebook.react.modules.timing.TimingModuleTest PASS 9.2s 9 Passed 0 Skipped 0 Failed com.facebook.react.packagerconnection.JSPackagerClientTest PASS 7.3s 4 Passed 0 Skipped 0 Failed com.facebook.react.uimanager.layoutanimation.InterpolatorTypeTest PASS 8.9s 2 Passed 0 Skipped 0 Failed com.facebook.react.uimanager.BaseViewManagerTest PASS 6.7s 4 Passed 0 Skipped 0 Failed com.facebook.react.uimanager.MatrixMathHelperTest PASS 8.8s 3 Passed 0 Skipped 0 Failed com.facebook.react.uimanager.SimpleViewPropertyTest PASS <100ms 1 Passed 0 Skipped 0 Failed com.facebook.react.util.JSStackTraceTest PASS 9.5s 1 Passed 0 Skipped 0 Failed com.facebook.react.views.image.ImageResizeModeTest PASS 15.7s 4 Passed 0 Skipped 0 Failed com.facebook.react.views.image.ReactImagePropertyTest PASS 9.2s 4 Passed 0 Skipped 0 Failed com.facebook.react.CompositeReactPackageTest PASS 9.2s 2 Passed 0 Skipped 0 Failed com.facebook.react.RootViewTest ``` Differential Revision: D19576473 Pulled By: shergin fbshipit-source-id: 35a6bce9f7dd3efec0cfcdbb00796852e1a79d6c --- Libraries/Components/ScrollView/ScrollView.js | 4 ++-- React/Views/ScrollView/RCTScrollView.m | 2 ++ .../com/facebook/react/views/scroll/ReactScrollView.java | 9 +++++++++ .../react/views/scroll/ReactScrollViewManager.java | 6 ++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 59f5517a9d8..51305ff5cce 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -401,8 +401,8 @@ export type Props = $ReadOnly<{| /** * When true, the scroll view stops on the next index (in relation to scroll * position at release) regardless of how fast the gesture is. This can be - * used for horizontal pagination when the page is less than the width of - * the ScrollView. The default value is false. + * used for pagination when the page is less than the width of the + * horizontal ScrollView or the height of the vertical ScrollView. The default value is false. */ disableIntervalMomentum?: ?boolean, /** diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index 4b4d46a50a1..a307cfe69e7 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -738,6 +738,8 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop) if (isHorizontal) { // Use current scroll offset to determine the next index to snap to when momentum disabled targetContentOffsetAlongAxis = self.disableIntervalMomentum ? scrollView.contentOffset.x : targetContentOffset->x; + } else { + targetContentOffsetAlongAxis = self.disableIntervalMomentum ? scrollView.contentOffset.y : targetContentOffset->y; } // Offset based on desired alignment diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index 10e1e443c95..48664a960ca 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -73,6 +73,7 @@ public class ReactScrollView extends ScrollView private @Nullable String mScrollPerfTag; private @Nullable Drawable mEndBackground; private int mEndFillColor = Color.TRANSPARENT; + private boolean mDisableIntervalMomentum = false; private int mSnapInterval = 0; private float mDecelerationRate = 0.985f; private @Nullable List mSnapOffsets; @@ -135,6 +136,10 @@ public class ReactScrollView extends ScrollView return scroller; } + public void setDisableIntervalMomentum(boolean disableIntervalMomentum) { + mDisableIntervalMomentum = disableIntervalMomentum; + } + public void setSendMomentumEvents(boolean sendMomentumEvents) { mSendMomentumEvents = sendMomentumEvents; } @@ -609,6 +614,10 @@ public class ReactScrollView extends ScrollView int maximumOffset = getMaxScrollY(); int targetOffset = predictFinalScrollPosition(velocityY); + if (mDisableIntervalMomentum) { + targetOffset = getScrollY(); + } + int smallerOffset = 0; int largerOffset = maximumOffset; int firstOffset = 0; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index d1bb2e4070c..0f435ad4aa6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -85,6 +85,12 @@ public class ReactScrollViewManager extends ViewGroupManager view.setDecelerationRate(decelerationRate); } + @ReactProp(name = "disableIntervalMomentum") + public void setDisableIntervalMomentum( + ReactScrollView view, boolean disbaleIntervalMomentum) { + view.setDisableIntervalMomentum(disbaleIntervalMomentum); + } + @ReactProp(name = "snapToInterval") public void setSnapToInterval(ReactScrollView view, float snapToInterval) { // snapToInterval needs to be exposed as a float because of the Javascript interface.