Skip to content

Commit 34c70f2

Browse files
authored
[iOS] Correctly attach Native gesture (#3802)
## Description `Native` gesture was incorrectly attached when underlying view was `UIControl`. This PR aims to fix this. It also changes `hostDetectorTag` to `hostDetectorView`, which simplifies `viewForEvents` logic. ## Test plan <details> <summary>Tested on the following code:</summary> ```tsx import { StyleSheet } from 'react-native'; import { GestureDetector, GestureHandlerRootView, PureNativeButton, useNative, } from 'react-native-gesture-handler'; const Button = ({ nativeGestureProperties }: any) => { const native = useNative(nativeGestureProperties); return ( <GestureDetector gesture={native}> <PureNativeButton style={{ width: 100, height: 20, backgroundColor: 'green' }} /> </GestureDetector> ); }; export default function App() { return ( <GestureHandlerRootView style={styles.container}> <Button nativeGestureProperties={{ onEnd: () => { console.log('end'); }, disableReanimated: true, }} /> </GestureHandlerRootView> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'space-around', alignItems: 'center', }, }); ``` </details>
1 parent 8d5eec6 commit 34c70f2

File tree

7 files changed

+60
-24
lines changed

7 files changed

+60
-24
lines changed

packages/react-native-gesture-handler/apple/RNGestureHandler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
@property (nonatomic) BOOL manualActivation;
8282
@property (nonatomic) BOOL dispatchesAnimatedEvents;
8383
@property (nonatomic) BOOL dispatchesReanimatedEvents;
84-
@property (nonatomic, nullable, assign) NSNumber *hostDetectorTag;
84+
@property (nonatomic, weak, nullable) RNGHUIView *hostDetectorView;
8585
@property (nonatomic, nullable, assign) NSNumber *virtualViewTag;
8686

8787
- (BOOL)isViewParagraphComponent:(nullable RNGHUIView *)view;
@@ -108,6 +108,7 @@
108108
- (nullable RNGHUIScrollView *)retrieveScrollView:(nonnull RNGHUIView *)view;
109109
- (nonnull RNGHUIView *)findViewForEvents;
110110
- (BOOL)wantsToAttachDirectlyToView;
111+
- (BOOL)usesNativeOrVirtualDetector;
111112

112113
#if !TARGET_OS_OSX
113114
- (BOOL)isUIScrollViewPanGestureRecognizer:(nonnull UIGestureRecognizer *)gestureRecognizer;

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@ - (UITouchType)getPointerType
229229
return (UITouchType)_pointerType;
230230
}
231231

232+
- (BOOL)usesNativeOrVirtualDetector
233+
{
234+
return _actionType == RNGestureHandlerActionTypeNativeDetector ||
235+
_actionType == RNGestureHandlerActionTypeVirtualDetector;
236+
}
237+
232238
- (BOOL)isViewParagraphComponent:(RNGHUIView *)view
233239
{
234240
return [view isKindOfClass:[RCTParagraphComponentView class]];
@@ -256,7 +262,7 @@ - (void)unbindFromView
256262
[self.recognizer.view removeGestureRecognizer:self.recognizer];
257263
self.recognizer.delegate = nil;
258264

259-
self.hostDetectorTag = nil;
265+
self.hostDetectorView = nil;
260266
self.virtualViewTag = nil;
261267

262268
[self unbindManualActivation];
@@ -389,10 +395,7 @@ - (void)sendEventsInState:(RNGestureHandlerState)state
389395

390396
- (RNGHUIView *)findViewForEvents
391397
{
392-
return
393-
[self isKindOfClass:[RNNativeViewGestureHandler class]] && _actionType == RNGestureHandlerActionTypeNativeDetector
394-
? self.recognizer.view.superview
395-
: self.recognizer.view;
398+
return [self usesNativeOrVirtualDetector] ? self.hostDetectorView : self.recognizer.view;
396399
}
397400

398401
- (void)sendEvent:(RNGestureHandlerStateChange *)event

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,27 @@ - (void)attachHandlers:(const std::vector<int> &)handlerTags
180180
RNGHUIView *targetView = [handlerManager viewForReactTag:@(viewTag)];
181181

182182
if (targetView != nil) {
183-
[handlerManager attachGestureHandler:@(tag) toViewWithTag:@(viewTag) withActionType:actionType];
183+
[handlerManager attachGestureHandler:@(tag)
184+
toViewWithTag:@(viewTag)
185+
withActionType:actionType
186+
withHostDetector:self];
184187
} else {
185188
// Let's assume that if the native view for the virtual detector hasn't been found, the hierarchy was folded
186189
// into a single UIView.
187-
[handlerManager.registry attachHandlerWithTag:@(tag) toView:self withActionType:actionType];
190+
[handlerManager.registry attachHandlerWithTag:@(tag)
191+
toView:self
192+
withActionType:actionType
193+
withHostDetector:self];
188194
[[handlerManager registry] handlerWithTag:@(tag)].virtualViewTag = @(viewTag);
189195
}
190196
} else {
191-
[handlerManager.registry attachHandlerWithTag:@(tag) toView:self withActionType:actionType];
197+
[handlerManager.registry attachHandlerWithTag:@(tag)
198+
toView:self
199+
withActionType:actionType
200+
withHostDetector:self];
192201
}
193202
[attachedHandlers addObject:@(tag)];
194203
}
195-
[[handlerManager registry] handlerWithTag:@(tag)].hostDetectorTag = @(self.tag);
196204
}
197205
}
198206

@@ -261,10 +269,20 @@ - (void)tryAttachNativeHandlersToChildView
261269
{
262270
RNGestureHandlerManager *handlerManager = [RNGestureHandlerModule handlerManagerForModuleId:_moduleId];
263271

272+
RNGHUIView *view = self.subviews[0];
273+
274+
if ([view isKindOfClass:[RCTViewComponentView class]]) {
275+
RCTViewComponentView *componentView = (RCTViewComponentView *)view;
276+
if (componentView.contentView != nil) {
277+
view = componentView.contentView;
278+
}
279+
}
280+
264281
for (NSNumber *handlerTag in _nativeHandlers) {
265282
[handlerManager.registry attachHandlerWithTag:handlerTag
266-
toView:self.subviews[0]
267-
withActionType:RNGestureHandlerActionTypeNativeDetector];
283+
toView:view
284+
withActionType:RNGestureHandlerActionTypeNativeDetector
285+
withHostDetector:self];
268286

269287
[_attachedHandlers addObject:handlerTag];
270288
}

packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
toViewWithTag:(nonnull NSNumber *)viewTag
2525
withActionType:(RNGestureHandlerActionType)actionType;
2626

27+
- (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
28+
toViewWithTag:(nonnull NSNumber *)viewTag
29+
withActionType:(RNGestureHandlerActionType)actionType
30+
withHostDetector:(nullable RNGHUIView *)hostDetector;
31+
2732
- (void)setGestureHandlerConfig:(nonnull NSNumber *)handlerTag config:(nonnull NSDictionary *)config;
2833

2934
- (void)updateGestureHandlerConfig:(nonnull NSNumber *)handlerTag config:(nonnull NSDictionary *)config;

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ - (void)createGestureHandler:(NSString *)handlerName tag:(NSNumber *)handlerTag
123123
- (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
124124
toViewWithTag:(nonnull NSNumber *)viewTag
125125
withActionType:(RNGestureHandlerActionType)actionType
126+
{
127+
[self attachGestureHandler:handlerTag toViewWithTag:viewTag withActionType:actionType withHostDetector:nil];
128+
}
129+
130+
- (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
131+
toViewWithTag:(nonnull NSNumber *)viewTag
132+
withActionType:(RNGestureHandlerActionType)actionType
133+
withHostDetector:(nullable RNGHUIView *)hostDetector
126134
{
127135
RNGHUIView *view = [_viewRegistry viewForReactTag:viewTag];
128136

@@ -151,7 +159,10 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
151159

152160
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
153161
if (![_droppedHandlers containsObject:handlerTag]) {
154-
[self attachGestureHandler:handlerTag toViewWithTag:viewTag withActionType:actionType];
162+
[self attachGestureHandler:handlerTag
163+
toViewWithTag:viewTag
164+
withActionType:actionType
165+
withHostDetector:hostDetector];
155166
}
156167
});
157168
}
@@ -173,7 +184,7 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
173184
view.reactTag = viewTag; // necessary for RNReanimated eventHash (e.g. "42onGestureHandlerEvent"), also will be
174185
// returned as event.target
175186

176-
[_registry attachHandlerWithTag:handlerTag toView:view withActionType:actionType];
187+
[_registry attachHandlerWithTag:handlerTag toView:view withActionType:actionType withHostDetector:hostDetector];
177188

178189
// register view if not already there
179190
[self registerViewWithGestureRecognizerAttachedIfNeeded:view];
@@ -295,15 +306,7 @@ - (void)sendEvent:(RNGestureHandlerStateChange *)event
295306
// but results in a compilation error.
296307
{
297308
switch (actionType) {
298-
case RNGestureHandlerActionTypeVirtualDetector: {
299-
NSNumber *hostDetectorTag = [_registry handlerWithTag:event.handlerTag].hostDetectorTag;
300-
detectorView = [self viewForReactTag:hostDetectorTag];
301-
[self sendNativeOrVirtualEvent:event
302-
withActionType:actionType
303-
forHandlerType:eventHandlerType
304-
forView:detectorView];
305-
break;
306-
}
309+
case RNGestureHandlerActionTypeVirtualDetector:
307310
case RNGestureHandlerActionTypeNativeDetector: {
308311
[self sendNativeOrVirtualEvent:event
309312
withActionType:actionType

packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
- (void)registerGestureHandler:(nonnull RNGestureHandler *)gestureHandler;
1515
- (void)attachHandlerWithTag:(nonnull NSNumber *)handlerTag
1616
toView:(nonnull RNGHUIView *)view
17-
withActionType:(RNGestureHandlerActionType)actionType;
17+
withActionType:(RNGestureHandlerActionType)actionType
18+
withHostDetector:(nullable RNGHUIView *)hostDetector;
1819
- (void)detachHandlerWithTag:(nonnull NSNumber *)handlerTag;
1920
- (void)dropHandlerWithTag:(nonnull NSNumber *)handlerTag;
2021
- (void)dropAllHandlers;

packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ - (void)registerGestureHandler:(RNGestureHandler *)gestureHandler
3535
- (void)attachHandlerWithTag:(NSNumber *)handlerTag
3636
toView:(RNGHUIView *)view
3737
withActionType:(RNGestureHandlerActionType)actionType
38+
withHostDetector:(nullable RNGHUIView *)hostDetector
3839
{
3940
RNGestureHandler *handler = _handlers[handlerTag];
4041
RCTAssert(handler != nil, @"Handler for tag %@ does not exists", handlerTag);
4142
[handler unbindFromView];
4243
handler.actionType = actionType;
4344
[handler bindToView:view];
45+
46+
if (hostDetector != nil) {
47+
handler.hostDetectorView = hostDetector;
48+
}
4449
}
4550

4651
- (void)detachHandlerWithTag:(NSNumber *)handlerTag

0 commit comments

Comments
 (0)