diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java index bc2ae48dfa868d..3e8dfa5730d7ca 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java @@ -7,6 +7,8 @@ package com.facebook.react.uimanager; +import java.util.Locale; + /** * Possible values for pointer events that a view and its descendants should receive. See * https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events for more info. @@ -25,4 +27,16 @@ public enum PointerEvents { /** Container and all of its children receive touch events (like pointerEvents is unspecified). */ AUTO, ; + + public static PointerEvents parsePointerEvents(String pointerEventsStr) { + return PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_")); + } + + public static boolean canBeTouchTarget(PointerEvents pointerEvents) { + return pointerEvents == AUTO || pointerEvents == PointerEvents.BOX_ONLY; + } + + public static boolean canChildrenBeTouchTarget(PointerEvents pointerEvents) { + return pointerEvents == PointerEvents.AUTO || pointerEvents == PointerEvents.BOX_NONE; + } } 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 cd10da2bf012c1..d5c141b07cff99 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 @@ -40,6 +40,7 @@ import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.FabricViewStateManager; import com.facebook.react.uimanager.MeasureSpecAssertions; +import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.react.uimanager.ReactOverflowViewWithInset; @@ -105,6 +106,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager(); private final ReactScrollViewScrollState mReactScrollViewScrollState; private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollX", 0, 0); + private PointerEvents mPointerEvents = PointerEvents.AUTO; private final Rect mTempRect = new Rect(); @@ -452,6 +454,11 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } + // We intercept the touch event if the children are not supposed to receive it. + if (!PointerEvents.canChildrenBeTouchTarget(mPointerEvents)) { + return true; + } + try { if (super.onInterceptTouchEvent(ev)) { NativeGestureUtil.notifyNativeGestureStarted(this, ev); @@ -519,6 +526,11 @@ public boolean onTouchEvent(MotionEvent ev) { return false; } + // We do not accept the touch event if this view is not supposed to receive it. + if (!PointerEvents.canBeTouchTarget(mPointerEvents)) { + return false; + } + mVelocityHelper.calculateVelocity(ev); int action = ev.getAction() & MotionEvent.ACTION_MASK; if (action == MotionEvent.ACTION_UP && mDragging) { @@ -1253,4 +1265,12 @@ public int getFlingExtrapolatedDistance(int velocityX) { this, velocityX, 0, Math.max(0, computeHorizontalScrollRange() - getWidth()), 0) .x; } + + public void setPointerEvents(PointerEvents pointerEvents) { + mPointerEvents = pointerEvents; + } + + public PointerEvents getPointerEvents() { + return mPointerEvents; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index d79e319960c81a..7c6a1891532620 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -16,6 +16,7 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.PixelUtil; +import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.Spacing; @@ -321,4 +322,13 @@ public void setContentOffset(ReactHorizontalScrollView view, ReadableMap value) view.scrollTo(0, 0); } } + + @ReactProp(name = ViewProps.POINTER_EVENTS) + public void setPointerEvents(ReactHorizontalScrollView view, @Nullable String pointerEventsStr) { + if (pointerEventsStr == null) { + view.setPointerEvents(PointerEvents.AUTO); + } else { + view.setPointerEvents(PointerEvents.parsePointerEvents(pointerEventsStr)); + } + } } 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 291da229ec703a..5ed2e040ba2bd8 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 @@ -36,6 +36,7 @@ import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.FabricViewStateManager; import com.facebook.react.uimanager.MeasureSpecAssertions; +import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.react.uimanager.ReactOverflowViewWithInset; @@ -102,6 +103,7 @@ public class ReactScrollView extends ScrollView private final ReactScrollViewScrollState mReactScrollViewScrollState = new ReactScrollViewScrollState(ViewCompat.LAYOUT_DIRECTION_LTR); private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollY", 0, 0); + private PointerEvents mPointerEvents = PointerEvents.AUTO; public ReactScrollView(Context context) { this(context, null); @@ -332,6 +334,11 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } + // We intercept the touch event if the children are not supposed to receive it. + if (!PointerEvents.canChildrenBeTouchTarget(mPointerEvents)) { + return true; + } + try { if (super.onInterceptTouchEvent(ev)) { NativeGestureUtil.notifyNativeGestureStarted(this, ev); @@ -357,6 +364,11 @@ public boolean onTouchEvent(MotionEvent ev) { return false; } + // We do not accept the touch event if this view is not supposed to receive it. + if (!PointerEvents.canBeTouchTarget(mPointerEvents)) { + return false; + } + mVelocityHelper.calculateVelocity(ev); int action = ev.getAction() & MotionEvent.ACTION_MASK; if (action == MotionEvent.ACTION_UP && mDragging) { @@ -1115,4 +1127,12 @@ public int getFlingExtrapolatedDistance(int velocityY) { return ReactScrollViewHelper.predictFinalScrollPosition(this, 0, velocityY, 0, getMaxScrollY()) .y; } + + public void setPointerEvents(PointerEvents pointerEvents) { + mPointerEvents = pointerEvents; + } + + public PointerEvents getPointerEvents() { + return mPointerEvents; + } } 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 3eb8aefafe769e..590aa49c8f4ff3 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 @@ -19,6 +19,7 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.PixelUtil; +import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.Spacing; @@ -363,4 +364,13 @@ public static Map createExportedCustomDirectEventTypeConstants() MapBuilder.of("registrationName", "onMomentumScrollEnd")) .build(); } + + @ReactProp(name = ViewProps.POINTER_EVENTS) + public void setPointerEvents(ReactScrollView view, @Nullable String pointerEventsStr) { + if (pointerEventsStr == null) { + view.setPointerEvents(PointerEvents.AUTO); + } else { + view.setPointerEvents(PointerEvents.parsePointerEvents(pointerEventsStr)); + } + } }