Skip to content

Commit 48f6967

Browse files
ryancatfacebook-github-bot
authored andcommitted
Add pointerEvents prop to RN Android scroll views
Summary: Per discussion in the previous diff D33672110, it's ok to add the `pointerEvents` prop to scrollview. This will help prevent scrolling on the ScrollView if pointerEvents is set to `box-none`, or `none`. Corresponding doc changes are in facebook/react-native-website#2936 Changelog: [Android][Added] - Add new API in ScrollView and HorizontalScrollView to process pointerEvents prop. Reviewed By: javache Differential Revision: D33699223 fbshipit-source-id: 1cae5113e9e7d988fc4c4765c41d817a321804c4
1 parent d0f0234 commit 48f6967

File tree

5 files changed

+74
-0
lines changed

5 files changed

+74
-0
lines changed

ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
package com.facebook.react.uimanager;
99

10+
import java.util.Locale;
11+
1012
/**
1113
* Possible values for pointer events that a view and its descendants should receive. See
1214
* https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events for more info.
@@ -25,4 +27,16 @@ public enum PointerEvents {
2527
/** Container and all of its children receive touch events (like pointerEvents is unspecified). */
2628
AUTO,
2729
;
30+
31+
public static PointerEvents parsePointerEvents(String pointerEventsStr) {
32+
return PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_"));
33+
}
34+
35+
public static boolean canBeTouchTarget(PointerEvents pointerEvents) {
36+
return pointerEvents == AUTO || pointerEvents == PointerEvents.BOX_ONLY;
37+
}
38+
39+
public static boolean canChildrenBeTouchTarget(PointerEvents pointerEvents) {
40+
return pointerEvents == PointerEvents.AUTO || pointerEvents == PointerEvents.BOX_NONE;
41+
}
2842
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java

+20
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.facebook.react.modules.i18nmanager.I18nUtil;
4141
import com.facebook.react.uimanager.FabricViewStateManager;
4242
import com.facebook.react.uimanager.MeasureSpecAssertions;
43+
import com.facebook.react.uimanager.PointerEvents;
4344
import com.facebook.react.uimanager.ReactClippingViewGroup;
4445
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
4546
import com.facebook.react.uimanager.ReactOverflowViewWithInset;
@@ -105,6 +106,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
105106
private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
106107
private final ReactScrollViewScrollState mReactScrollViewScrollState;
107108
private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollX", 0, 0);
109+
private PointerEvents mPointerEvents = PointerEvents.AUTO;
108110

109111
private final Rect mTempRect = new Rect();
110112

@@ -452,6 +454,11 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
452454
return false;
453455
}
454456

457+
// We intercept the touch event if the children are not supposed to receive it.
458+
if (!PointerEvents.canChildrenBeTouchTarget(mPointerEvents)) {
459+
return true;
460+
}
461+
455462
try {
456463
if (super.onInterceptTouchEvent(ev)) {
457464
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
@@ -519,6 +526,11 @@ public boolean onTouchEvent(MotionEvent ev) {
519526
return false;
520527
}
521528

529+
// We do not accept the touch event if this view is not supposed to receive it.
530+
if (!PointerEvents.canBeTouchTarget(mPointerEvents)) {
531+
return false;
532+
}
533+
522534
mVelocityHelper.calculateVelocity(ev);
523535
int action = ev.getAction() & MotionEvent.ACTION_MASK;
524536
if (action == MotionEvent.ACTION_UP && mDragging) {
@@ -1253,4 +1265,12 @@ public int getFlingExtrapolatedDistance(int velocityX) {
12531265
this, velocityX, 0, Math.max(0, computeHorizontalScrollRange() - getWidth()), 0)
12541266
.x;
12551267
}
1268+
1269+
public void setPointerEvents(PointerEvents pointerEvents) {
1270+
mPointerEvents = pointerEvents;
1271+
}
1272+
1273+
public PointerEvents getPointerEvents() {
1274+
return mPointerEvents;
1275+
}
12561276
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.facebook.react.module.annotations.ReactModule;
1717
import com.facebook.react.uimanager.DisplayMetricsHolder;
1818
import com.facebook.react.uimanager.PixelUtil;
19+
import com.facebook.react.uimanager.PointerEvents;
1920
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
2021
import com.facebook.react.uimanager.ReactStylesDiffMap;
2122
import com.facebook.react.uimanager.Spacing;
@@ -321,4 +322,13 @@ public void setContentOffset(ReactHorizontalScrollView view, ReadableMap value)
321322
view.scrollTo(0, 0);
322323
}
323324
}
325+
326+
@ReactProp(name = ViewProps.POINTER_EVENTS)
327+
public void setPointerEvents(ReactHorizontalScrollView view, @Nullable String pointerEventsStr) {
328+
if (pointerEventsStr == null) {
329+
view.setPointerEvents(PointerEvents.AUTO);
330+
} else {
331+
view.setPointerEvents(PointerEvents.parsePointerEvents(pointerEventsStr));
332+
}
333+
}
324334
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java

+20
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.facebook.react.common.ReactConstants;
3737
import com.facebook.react.uimanager.FabricViewStateManager;
3838
import com.facebook.react.uimanager.MeasureSpecAssertions;
39+
import com.facebook.react.uimanager.PointerEvents;
3940
import com.facebook.react.uimanager.ReactClippingViewGroup;
4041
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
4142
import com.facebook.react.uimanager.ReactOverflowViewWithInset;
@@ -102,6 +103,7 @@ public class ReactScrollView extends ScrollView
102103
private final ReactScrollViewScrollState mReactScrollViewScrollState =
103104
new ReactScrollViewScrollState(ViewCompat.LAYOUT_DIRECTION_LTR);
104105
private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollY", 0, 0);
106+
private PointerEvents mPointerEvents = PointerEvents.AUTO;
105107

106108
public ReactScrollView(Context context) {
107109
this(context, null);
@@ -332,6 +334,11 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
332334
return false;
333335
}
334336

337+
// We intercept the touch event if the children are not supposed to receive it.
338+
if (!PointerEvents.canChildrenBeTouchTarget(mPointerEvents)) {
339+
return true;
340+
}
341+
335342
try {
336343
if (super.onInterceptTouchEvent(ev)) {
337344
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
@@ -357,6 +364,11 @@ public boolean onTouchEvent(MotionEvent ev) {
357364
return false;
358365
}
359366

367+
// We do not accept the touch event if this view is not supposed to receive it.
368+
if (!PointerEvents.canBeTouchTarget(mPointerEvents)) {
369+
return false;
370+
}
371+
360372
mVelocityHelper.calculateVelocity(ev);
361373
int action = ev.getAction() & MotionEvent.ACTION_MASK;
362374
if (action == MotionEvent.ACTION_UP && mDragging) {
@@ -1115,4 +1127,12 @@ public int getFlingExtrapolatedDistance(int velocityY) {
11151127
return ReactScrollViewHelper.predictFinalScrollPosition(this, 0, velocityY, 0, getMaxScrollY())
11161128
.y;
11171129
}
1130+
1131+
public void setPointerEvents(PointerEvents pointerEvents) {
1132+
mPointerEvents = pointerEvents;
1133+
}
1134+
1135+
public PointerEvents getPointerEvents() {
1136+
return mPointerEvents;
1137+
}
11181138
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java

+10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.facebook.react.module.annotations.ReactModule;
2020
import com.facebook.react.uimanager.DisplayMetricsHolder;
2121
import com.facebook.react.uimanager.PixelUtil;
22+
import com.facebook.react.uimanager.PointerEvents;
2223
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
2324
import com.facebook.react.uimanager.ReactStylesDiffMap;
2425
import com.facebook.react.uimanager.Spacing;
@@ -363,4 +364,13 @@ public static Map<String, Object> createExportedCustomDirectEventTypeConstants()
363364
MapBuilder.of("registrationName", "onMomentumScrollEnd"))
364365
.build();
365366
}
367+
368+
@ReactProp(name = ViewProps.POINTER_EVENTS)
369+
public void setPointerEvents(ReactScrollView view, @Nullable String pointerEventsStr) {
370+
if (pointerEventsStr == null) {
371+
view.setPointerEvents(PointerEvents.AUTO);
372+
} else {
373+
view.setPointerEvents(PointerEvents.parsePointerEvents(pointerEventsStr));
374+
}
375+
}
366376
}

0 commit comments

Comments
 (0)