From c06f765f7d73077feee1285dc56f01a32e63fe0c Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 29 Sep 2020 13:16:57 -0700 Subject: [PATCH] Allow Java classes to hook into ScrollView scroll and layout events Summary: For advanced interop cases. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D23984345 fbshipit-source-id: f5c2a43a1bf5937f9974bcc5c66c36ec35e679c5 --- .../scroll/ReactHorizontalScrollView.java | 1 + .../react/views/scroll/ReactScrollView.java | 1 + .../views/scroll/ReactScrollViewHelper.java | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 61b1a712332..b632671b712 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -266,6 +266,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView int scrollToY = pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); reactScrollTo(scrollToX, scrollToY); + ReactScrollViewHelper.emitLayoutEvent(this); } /** 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 6497c6bce98..118579c886f 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 @@ -223,6 +223,7 @@ public class ReactScrollView extends ScrollView int scrollToY = pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); reactScrollTo(scrollToX, scrollToY); + ReactScrollViewHelper.emitLayoutEvent(this); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java index 5183f24c44b..c10a38ebdb0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java @@ -14,6 +14,8 @@ import android.widget.OverScroller; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReactContext; import com.facebook.react.uimanager.UIManagerHelper; +import java.util.ArrayList; +import java.util.List; /** Helper class that deals with emitting Scroll Events. */ public class ReactScrollViewHelper { @@ -23,6 +25,16 @@ public class ReactScrollViewHelper { public static final String AUTO = "auto"; public static final String OVER_SCROLL_NEVER = "never"; + public interface ScrollListener { + void onScroll( + ViewGroup scrollView, ScrollEventType scrollEventType, float xVelocity, float yVelocity); + + void onLayout(ViewGroup scrollView); + } + + // Support global native listeners for scroll events + private static List sScrollListeners = new ArrayList<>(); + // If all else fails, this is the hardcoded value in OverScroller.java, in AOSP. // The default is defined here (as of this diff): // https://android.googlesource.com/platform/frameworks/base/+/ae5bcf23b5f0875e455790d6af387184dbd009c1/core/java/android/widget/OverScroller.java#44 @@ -64,6 +76,10 @@ public class ReactScrollViewHelper { return; } + for (ScrollListener scrollListener : sScrollListeners) { + scrollListener.onScroll(scrollView, scrollEventType, xVelocity, yVelocity); + } + ReactContext reactContext = (ReactContext) scrollView.getContext(); UIManagerHelper.getEventDispatcherForReactTag(reactContext, scrollView.getId()) .dispatchEvent( @@ -80,6 +96,13 @@ public class ReactScrollViewHelper { scrollView.getHeight())); } + /** This is only for Java listeners. onLayout events emitted to JS are handled elsewhere. */ + public static void emitLayoutEvent(ViewGroup scrollView) { + for (ScrollListener scrollListener : sScrollListeners) { + scrollListener.onLayout(scrollView); + } + } + public static int parseOverScrollMode(String jsOverScrollMode) { if (jsOverScrollMode == null || jsOverScrollMode.equals(AUTO)) { return View.OVER_SCROLL_IF_CONTENT_SCROLLS; @@ -130,4 +153,12 @@ public class ReactScrollViewHelper { mScrollAnimationDuration = duration; } } + + public static void addScrollListener(ScrollListener listener) { + sScrollListeners.add(listener); + } + + public static void removeScrollListener(ScrollListener listener) { + sScrollListeners.remove(listener); + } }