Skip to content

Commit 4d5aae1

Browse files
j-piaseckitomekzaw
andauthored
Correctly attach root view recognizer in modals on iOS (#2498)
## Description On iOS, the conditions to attach `RootViewGestureRecognizer` were satisfied neither on the new nor the old architecture. This PR changes this logic: - unifies extracting the RN's touch handler to simply loop on all recognizers attached to the root view, as it works in every case - adds a check for `ModalHostViewController` when attaching the root view recognizer and if the view is in the modal the logic is different: - on the old arch: [RCTModalHostView](https://github.com/facebook/react-native/blob/b50874cad41f06519a263fa53d15f76c836fd167/packages/react-native/React/Views/RCTModalHostView.m#L95-L100) has a `UIView` as its child, and this one may only have one `RCTView` as its child - this one has the `RCTTouchHandler` recognizer attached - on the new arch: [RCTFabricModalHostViewController](https://github.com/facebook/react-native/blob/b50874cad41f06519a263fa53d15f76c836fd167/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.mm#L42) directly attaches `RCTSurfaceTouchHandler` to its direct subview Fixes #2487. ## Test plan Tested on Example and FabricExample apps and on the code from the issue. --------- Co-authored-by: Tomek Zawadzki <tomekzawadzki98@gmail.com>
1 parent 69b034a commit 4d5aae1

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

ios/RNGestureHandlerManager.mm

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#import <React/RCTComponent.h>
44
#import <React/RCTEventDispatcher.h>
55
#import <React/RCTLog.h>
6+
#import <React/RCTModalHostViewController.h>
67
#import <React/RCTRootContentView.h>
78
#import <React/RCTRootView.h>
89
#import <React/RCTUIManager.h>
@@ -15,6 +16,7 @@
1516
#import "RNRootViewGestureRecognizer.h"
1617

1718
#ifdef RCT_NEW_ARCH_ENABLED
19+
#import <React/RCTFabricModalHostViewController.h>
1820
#import <React/RCTSurfaceTouchHandler.h>
1921
#import <React/RCTSurfaceView.h>
2022
#import <React/RCTViewComponentView.h>
@@ -199,15 +201,26 @@ - (void)registerViewWithGestureRecognizerAttachedIfNeeded:(UIView *)childView
199201
#ifdef RCT_NEW_ARCH_ENABLED
200202
UIView *touchHandlerView = childView;
201203

202-
while (touchHandlerView != nil && ![touchHandlerView isKindOfClass:[RCTSurfaceView class]]) {
203-
touchHandlerView = touchHandlerView.superview;
204+
if ([[childView reactViewController] isKindOfClass:[RCTFabricModalHostViewController class]]) {
205+
touchHandlerView = [childView reactViewController].view;
206+
} else {
207+
while (touchHandlerView != nil && ![touchHandlerView isKindOfClass:[RCTSurfaceView class]]) {
208+
touchHandlerView = touchHandlerView.superview;
209+
}
204210
}
205211
#else
206-
UIView *parent = childView;
207-
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)])
208-
parent = parent.superview;
212+
UIView *touchHandlerView = nil;
213+
214+
if ([[childView reactViewController] isKindOfClass:[RCTModalHostViewController class]]) {
215+
touchHandlerView = [childView reactViewController].view.subviews[0];
216+
} else {
217+
UIView *parent = childView;
218+
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) {
219+
parent = parent.superview;
220+
}
209221

210-
UIView *touchHandlerView = [[parent performSelector:@selector(touchHandler)] view];
222+
touchHandlerView = [[parent performSelector:@selector(touchHandler)] view];
223+
}
211224
#endif // RCT_NEW_ARCH_ENABLED
212225

213226
if (touchHandlerView == nil) {
@@ -247,20 +260,19 @@ - (void)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
247260
if ([gestureRecognizer.view isKindOfClass:[UIScrollView class]])
248261
return;
249262

250-
#ifdef RCT_NEW_ARCH_ENABLED
251263
UIGestureRecognizer *touchHandler = nil;
252264

253-
// touchHandler (RCTSurfaceTouchHandler) is private in RCTFabricSurface so we have to do
254-
// this little trick to get access to it
265+
// this way we can extract the touch handler on both architectures relatively easily
255266
for (UIGestureRecognizer *recognizer in [viewWithTouchHandler gestureRecognizers]) {
267+
#ifdef RCT_NEW_ARCH_ENABLED
256268
if ([recognizer isKindOfClass:[RCTSurfaceTouchHandler class]]) {
269+
#else
270+
if ([recognizer isKindOfClass:[RCTTouchHandler class]]) {
271+
#endif // RCT_NEW_ARCH_ENABLED
257272
touchHandler = recognizer;
258273
break;
259274
}
260275
}
261-
#else
262-
RCTTouchHandler *touchHandler = [viewWithTouchHandler performSelector:@selector(touchHandler)];
263-
#endif // RCT_NEW_ARCH_ENABLED
264276
[touchHandler setEnabled:NO];
265277
[touchHandler setEnabled:YES];
266278
}

0 commit comments

Comments
 (0)