Skip to content

Commit b776a81

Browse files
authored
fix(android): handles pointerEvents for Pressable component (#3927)
## Description fixes: #3891 fixes: #3904 This PR fixes `pointerEvents` support for `Pressable` component from `react-native-gesture-handler` on Android. Waiting for iOS PR: #3925 as codegen is involved and a small iOS changes is needed ## Test plan Tested all `pointerEvents` modes on Android: - ✅ `pointerEvents="none"` - View and subviews don't receive touches - ✅ `pointerEvents="box-none"` - View doesn't receive touches, subviews do - ✅ `pointerEvents="box-only"` - View receives touches, subviews don't - ✅ `pointerEvents="auto"` - Default behavior works as expected I've used https://github.com/huextrat/repro-pressable-gh to test scenarios Tested on both old architecture (Paper) and new architecture (Fabric).
1 parent 59a5311 commit b776a81

File tree

5 files changed

+34
-4
lines changed

5 files changed

+34
-4
lines changed

packages/react-native-gesture-handler/android/paper/src/main/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public void setProperty(T view, String propName, @Nullable Object value) {
5454
case "borderStyle":
5555
mViewManager.setBorderStyle(view, value == null ? "solid" : (String) value);
5656
break;
57+
case "pointerEvents":
58+
mViewManager.setPointerEvents(view, (String) value);
59+
break;
5760
default:
5861
super.setProperty(view, propName, value);
5962
}

packages/react-native-gesture-handler/android/paper/src/main/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ public interface RNGestureHandlerButtonManagerInterface<T extends View> extends
2424
void setBorderWidth(T view, float value);
2525
void setBorderColor(T view, @Nullable Integer value);
2626
void setBorderStyle(T view, @Nullable String value);
27+
void setPointerEvents(T view, @Nullable String value);
2728
}

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import androidx.core.view.children
2727
import com.facebook.react.R
2828
import com.facebook.react.module.annotations.ReactModule
2929
import com.facebook.react.uimanager.PixelUtil
30+
import com.facebook.react.uimanager.PointerEvents
31+
import com.facebook.react.uimanager.ReactPointerEventsView
3032
import com.facebook.react.uimanager.ThemedReactContext
3133
import com.facebook.react.uimanager.ViewGroupManager
3234
import com.facebook.react.uimanager.ViewManagerDelegate
@@ -132,6 +134,17 @@ class RNGestureHandlerButtonViewManager :
132134
view.isSoundEffectsEnabled = !touchSoundDisabled
133135
}
134136

137+
@ReactProp(name = ViewProps.POINTER_EVENTS)
138+
override fun setPointerEvents(view: ButtonViewGroup, pointerEvents: String?) {
139+
view.pointerEvents = when (pointerEvents) {
140+
"none" -> PointerEvents.NONE
141+
"box-none" -> PointerEvents.BOX_NONE
142+
"box-only" -> PointerEvents.BOX_ONLY
143+
"auto", null -> PointerEvents.AUTO
144+
else -> PointerEvents.AUTO
145+
}
146+
}
147+
135148
override fun onAfterUpdateTransaction(view: ButtonViewGroup) {
136149
super.onAfterUpdateTransaction(view)
137150

@@ -142,7 +155,8 @@ class RNGestureHandlerButtonViewManager :
142155

143156
class ButtonViewGroup(context: Context?) :
144157
ViewGroup(context),
145-
NativeViewGestureHandler.NativeViewGestureHandlerHook {
158+
NativeViewGestureHandler.NativeViewGestureHandlerHook,
159+
ReactPointerEventsView {
146160
// Using object because of handling null representing no value set.
147161
var rippleColor: Int? = null
148162
set(color) = withBackgroundUpdate {
@@ -200,6 +214,8 @@ class RNGestureHandlerButtonViewManager :
200214

201215
var exclusive = true
202216

217+
override var pointerEvents: PointerEvents = PointerEvents.AUTO
218+
203219
private var buttonBackgroundColor = Color.TRANSPARENT
204220
private var needBackgroundUpdate = false
205221
private var lastEventTime = -1L

packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,17 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
223223
_buttonView.hitTestEdgeInsets = UIEdgeInsetsMake(
224224
-newProps.hitSlop.top, -newProps.hitSlop.left, -newProps.hitSlop.bottom, -newProps.hitSlop.right);
225225

226+
// We need to cast to ViewProps to access the pointerEvents property with the correct type.
227+
// This is necessary because pointerEvents is redefined in the spec,
228+
// which shadows the base property with a different, incompatible type.
229+
const auto &newViewProps = static_cast<const ViewProps &>(newProps);
226230
if (!oldProps) {
227-
_buttonView.pointerEvents = RCTPointerEventsToEnum(newProps.pointerEvents);
231+
_buttonView.pointerEvents = RCTPointerEventsToEnum(newViewProps.pointerEvents);
228232
} else {
229233
const auto &oldButtonProps = *std::static_pointer_cast<const RNGestureHandlerButtonProps>(oldProps);
230-
if (oldButtonProps.pointerEvents != newProps.pointerEvents) {
231-
_buttonView.pointerEvents = RCTPointerEventsToEnum(newProps.pointerEvents);
234+
const auto &oldViewProps = static_cast<const ViewProps &>(oldButtonProps);
235+
if (oldViewProps.pointerEvents != newViewProps.pointerEvents) {
236+
_buttonView.pointerEvents = RCTPointerEventsToEnum(newViewProps.pointerEvents);
232237
}
233238
}
234239

packages/react-native-gesture-handler/src/specs/RNGestureHandlerButtonNativeComponent.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
} from 'react-native/Libraries/Types/CodegenTypes';
77
import type { ViewProps, ColorValue } from 'react-native';
88

9+
// @ts-ignore - Redefining pointerEvents with WithDefault for codegen, conflicts with ViewProps type but codegen needs it
910
interface NativeProps extends ViewProps {
1011
exclusive?: WithDefault<boolean, true>;
1112
foreground?: boolean;
@@ -17,6 +18,10 @@ interface NativeProps extends ViewProps {
1718
borderWidth?: Float;
1819
borderColor?: ColorValue;
1920
borderStyle?: WithDefault<string, 'solid'>;
21+
pointerEvents?: WithDefault<
22+
'box-none' | 'none' | 'box-only' | 'auto',
23+
'auto'
24+
>;
2025
}
2126

2227
export default codegenNativeComponent<NativeProps>('RNGestureHandlerButton');

0 commit comments

Comments
 (0)