Skip to content

Commit

Permalink
Add category on UIView with code for touch handler finding
Browse files Browse the repository at this point in the history
  • Loading branch information
kkafar committed Jun 18, 2024
1 parent 84f8f6d commit aca213c
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
23 changes: 23 additions & 0 deletions ios/utils/UIView+RNSUtility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#import <Foundation/Foundation.h>

#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTSurfaceTouchHandler.h>
#else
#import <React/RCTTouchHandler.h>
#endif // RCT_NEW_ARCH_ENABLED

#ifdef RCT_NEW_ARCH_ENABLED
#define RNS_TOUCH_HANDLER_ARCH_TYPE RCTSurfaceTouchHandler
#else
#define RNS_TOUCH_HANDLER_ARCH_TYPE RCTTouchHandler
#endif // RCT_NEW_ARCH_ENABLED

NS_ASSUME_NONNULL_BEGIN

@interface UIView (RNSUtility)

- (nullable RNS_TOUCH_HANDLER_ARCH_TYPE *)rnscreens_findTouchHandlerInAncestorChain;

@end

NS_ASSUME_NONNULL_END
55 changes: 55 additions & 0 deletions ios/utils/UIView+RNSUtility.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

#import "UIView+RNSUtility.h"

#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTSurfaceView.h>
#endif

@implementation UIView (RNSUtility)

- (nullable RNS_TOUCH_HANDLER_ARCH_TYPE *)rnscreens_findTouchHandlerInAncestorChain
{
UIView *parent = self;

#ifdef RCT_NEW_ARCH_ENABLED
// On Fabric there is no view that exposes touchHandler above us in the view hierarchy, however it is still
// utilised. `RCTSurfaceView` should be present above us, which hosts `RCTFabricSurface` instance, which in turn
// hosts `RCTSurfaceTouchHandler` as a private field. When initialised, `RCTSurfaceTouchHandler` is attached to the
// surface view as a gestureRecognizer <- and this is where we can lay our hands on it.

while (parent != nil && ![parent isKindOfClass:RCTSurfaceView.class]) {
parent = parent.superview;
}

// This could be possible in modal context
if (parent == nil) {
return nil;
}

// Experimentation shows that RCTSurfaceTouchHandler is the only gestureRecognizer registered here,
// so we should not be afraid of any performance hit here.
for (UIGestureRecognizer *recognizer in parent.gestureRecognizers) {
if ([recognizer isKindOfClass:RCTSurfaceTouchHandler.class]) {
return static_cast<RNS_TOUCH_HANDLER_ARCH_TYPE *>(recognizer);
}
}

#else

// On Paper we can access touchHandler hosted by `RCTRootContentView` which should be above ScreenStack
// in view hierarchy.
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) {
parent = parent.superview;
}

if (parent != nil) {
RCTTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
return static_cast<RNS_TOUCH_HANDLER_ARCH_TYPE *>(touchHandler);
}

#endif // RCT_NEW_ARCH_ENABLED

return nil;
}

@end

0 comments on commit aca213c

Please sign in to comment.