Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #import "RNGestureHandlerManager.h"
- #import <React/RCTLog.h>
- #import <React/RCTViewManager.h>
- #import <React/RCTComponent.h>
- #import <React/RCTRootView.h>
- #import <React/RCTTouchHandler.h>
- #import "RCTRootContentView.h"
- #import "RNGestureHandlerState.h"
- #import "RNGestureHandler.h"
- #import "RNGestureHandlerRegistry.h"
- #import "RNRootViewGestureRecognizer.h"
- #import "Handlers/RNPanHandler.h"
- #import "Handlers/RNTapHandler.h"
- #import "Handlers/RNFlingHandler.h"
- #import "Handlers/RNLongPressHandler.h"
- #import "Handlers/RNNativeViewHandler.h"
- #import "Handlers/RNPinchHandler.h"
- #import "Handlers/RNRotationHandler.h"
- #import "Handlers/RNForceTouchHandler.h"
- // We use the method below instead of RCTLog because we log out messages after the bridge gets
- // turned down in some cases. Which normally with RCTLog would cause a crash in DEBUG mode
- #define RCTLifecycleLog(...) RCTDefaultLogFunction(RCTLogLevelInfo, RCTLogSourceNative, @(__FILE__), @(__LINE__), [NSString stringWithFormat:__VA_ARGS__])
- @interface RNGestureHandlerManager () <RNGestureHandlerEventEmitter, RNRootViewGestureRecognizerDelegate>
- @end
- @implementation RNGestureHandlerManager
- {
- RNGestureHandlerRegistry *_registry;
- RCTUIManager *_uiManager;
- NSMutableSet<UIView*> *_rootViews;
- RCTEventDispatcher *_eventDispatcher;
- }
- - (instancetype)initWithUIManager:(RCTUIManager *)uiManager
- eventDispatcher:(RCTEventDispatcher *)eventDispatcher
- {
- if ((self = [super init])) {
- _uiManager = uiManager;
- _eventDispatcher = eventDispatcher;
- _registry = [RNGestureHandlerRegistry new];
- _rootViews = [NSMutableSet new];
- }
- return self;
- }
- - (void)createGestureHandler:(NSString *)handlerName
- tag:(NSNumber *)handlerTag
- config:(NSDictionary *)config
- {
- static NSDictionary *map;
- static dispatch_once_t mapToken;
- dispatch_once(&mapToken, ^{
- map = @{
- @"PanGestureHandler" : [RNPanGestureHandler class],
- @"TapGestureHandler" : [RNTapGestureHandler class],
- @"FlingGestureHandler" : [RNFlingGestureHandler class],
- @"LongPressGestureHandler": [RNLongPressGestureHandler class],
- @"NativeViewGestureHandler": [RNNativeViewGestureHandler class],
- @"PinchGestureHandler": [RNPinchGestureHandler class],
- @"RotationGestureHandler": [RNRotationGestureHandler class],
- @"ForceTouchGestureHandler": [RNForceTouchHandler class],
- };
- });
- Class nodeClass = map[handlerName];
- if (!nodeClass) {
- RCTLogError(@"Gesture handler type %@ is not supported", handlerName);
- return;
- }
- RNGestureHandler *gestureHandler = [[nodeClass alloc] initWithTag:handlerTag];
- [gestureHandler configure:config];
- [_registry registerGestureHandler:gestureHandler];
- __weak id<RNGestureHandlerEventEmitter> emitter = self;
- gestureHandler.emitter = emitter;
- }
- - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
- toViewWithTag:(nonnull NSNumber *)viewTag
- {
- UIView *view = [_uiManager viewForReactTag:viewTag];
- [_registry attachHandlerWithTag:handlerTag toView:view];
- // register root view if not already there
- [self registerRootViewIfNeeded:view];
- }
- - (void)updateGestureHandler:(NSNumber *)handlerTag config:(NSDictionary *)config
- {
- RNGestureHandler *handler = [_registry handlerWithTag:handlerTag];
- [handler configure:config];
- }
- - (void)dropGestureHandler:(NSNumber *)handlerTag
- {
- [_registry dropHandlerWithTag:handlerTag];
- }
- - (void)handleSetJSResponder:(NSNumber *)viewTag blockNativeResponder:(NSNumber *)blockNativeResponder
- {
- if ([blockNativeResponder boolValue]) {
- for (RCTRootView *rootView in _rootViews) {
- for (UIGestureRecognizer *recognizer in rootView.gestureRecognizers) {
- if ([recognizer isKindOfClass:[RNRootViewGestureRecognizer class]]) {
- [(RNRootViewGestureRecognizer *)recognizer blockOtherRecognizers];
- }
- }
- }
- }
- }
- - (void)handleClearJSResponder
- {
- // ignore...
- }
- #pragma mark Root Views Management
- - (void)registerRootViewIfNeeded:(UIView*)childView
- {
- UIView *parent = childView;
- while (parent != nil && ![parent isKindOfClass:[RCTRootView class]]) parent = parent.superview;
- RCTRootView *rootView = (RCTRootView *)parent;
- UIView *rootContentView = rootView.contentView;
- if (rootContentView != nil && ![_rootViews containsObject:rootContentView]) {
- RCTLifecycleLog(@"[GESTURE HANDLER] Initialize gesture handler for root view %@", rootContentView);
- [_rootViews addObject:rootContentView];
- RNRootViewGestureRecognizer *recognizer = [RNRootViewGestureRecognizer new];
- recognizer.delegate = self;
- rootContentView.userInteractionEnabled = YES;
- [rootContentView addGestureRecognizer:recognizer];
- }
- }
- - (void)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
- didActivateInRootView:(UIView *)rootContentView
- {
- // Cancel touches in RN's root view in order to cancel all in-js recognizers
- // As scroll events are special-cased in RN responder implementation and sending them would
- // trigger JS responder change, we don't cancel touches if the handler that got activated is
- // a scroll recognizer. This way root view will keep sending touchMove and touchEnd events
- // and therefore allow JS responder to properly release the responder at the end of the touch
- // stream.
- // NOTE: this is not a proper fix and solving this problem requires upstream fixes to RN. In
- // particular if we have one PanHandler and ScrollView that can work simultaniously then when
- // the Pan handler activates it would still tigger cancel events.
- // Once the upstream fix lands the line below along with this comment can be removed
- if ([gestureRecognizer.view isKindOfClass:[UIScrollView class]]) return;
- UIView *parent = rootContentView.superview;
- if ([parent isKindOfClass:[RCTRootView class]]) {
- [((RCTRootContentView*)rootContentView).touchHandler cancel];
- }
- }
- - (void)dealloc
- {
- if ([_rootViews count] > 0) {
- RCTLifecycleLog(@"[GESTURE HANDLER] Tearing down gesture handler registered for views %@", _rootViews);
- }
- }
- #pragma mark Events
- - (void)sendTouchEvent:(RNGestureHandlerEvent *)event
- {
- [_eventDispatcher sendEvent:event];
- }
- - (void)sendStateChangeEvent:(RNGestureHandlerStateChange *)event
- {
- [_eventDispatcher sendEvent:event];
- }
- @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement