Skip to content

Fix native gesture reattach #3672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
private val reactContext: ThemedReactContext
get() = context as ThemedReactContext
private var handlersToAttach: List<Int>? = null
private var nativeHandlersToAttach: MutableSet<Int> = mutableSetOf()
private var nativeHandlers: MutableSet<Int> = mutableSetOf()
private var attachedHandlers: MutableSet<Int> = mutableSetOf()
private var moduleId: Int = -1

Expand Down Expand Up @@ -48,7 +48,7 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
override fun addView(child: View, index: Int, params: LayoutParams?) {
super.addView(child, index, params)

tryAttachHandlerToChildView(child.id)
tryAttachNativeHandlersToChildView(child.id)
}

override fun removeViewAt(index: Int) {
Expand Down Expand Up @@ -78,14 +78,15 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
// It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot
// attach `NativeViewGestureHandlers` here and we have to do it in `addView` method.
if (shouldAttachGestureToChildView(tag)) {
nativeHandlersToAttach.add(tag)
nativeHandlers.add(tag)
} else {
registry.attachHandlerToView(tag, this.id, GestureHandler.ACTION_TYPE_NATIVE_DETECTOR)

attachedHandlers.add(tag)
}
} else if (entry.value == GestureHandlerMutation.Detach) {
registry.detachHandler(tag)
nativeHandlers.remove(tag)
attachedHandlers.remove(tag)
}
}
Expand All @@ -94,32 +95,28 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
val child = getChildAt(0)

if (child != null) {
tryAttachHandlerToChildView(child.id)
tryAttachNativeHandlersToChildView(child.id)
}
}

private fun tryAttachHandlerToChildView(childId: Int) {
private fun tryAttachNativeHandlersToChildView(childId: Int) {
val registry = RNGestureHandlerModule.registries[moduleId]
?: throw Exception("Tried to access a non-existent registry")

for (tag in nativeHandlersToAttach) {
for (tag in nativeHandlers) {
registry.attachHandlerToView(tag, childId, GestureHandler.ACTION_TYPE_NATIVE_DETECTOR)

attachedHandlers.add(tag)
}

nativeHandlersToAttach.clear()
}

private fun detachNativeGestureHandlers() {
val registry = RNGestureHandlerModule.registries[moduleId]
?: throw Exception("Tried to access a non-existent registry")

for (tag in attachedHandlers) {
if (shouldAttachGestureToChildView(tag)) {
registry.detachHandler(tag)
attachedHandlers.remove(tag)
}
for (tag in nativeHandlers) {
registry.detachHandler(tag)
attachedHandlers.remove(tag)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN

- (void)dispatchTouchEvent:(RNGestureHandlerDetectorEventEmitter::OnGestureHandlerTouchEvent)event;

- (void)tryAttachHandlerToChildView;
- (void)tryAttachNativeHandlersToChildView;

- (void)detachNativeGestureHandlers;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

@interface RNGestureHandlerDetector () <RCTRNGestureHandlerDetectorViewProtocol>

@property (nonatomic, nonnull) NSMutableSet *nativeHandlersToAttach;
@property (nonatomic, nonnull) NSMutableSet *nativeHandlers;
@property (nonatomic, nonnull) NSMutableSet *attachedHandlers;

@end
Expand Down Expand Up @@ -41,7 +41,7 @@ - (instancetype)initWithFrame:(CGRect)frame
static const auto defaultProps = std::make_shared<const RNGestureHandlerDetectorProps>();
_props = defaultProps;
_moduleId = -1;
_nativeHandlersToAttach = [NSMutableSet set];
_nativeHandlers = [NSMutableSet set];
_attachedHandlers = [NSMutableSet set];
}

Expand Down Expand Up @@ -94,11 +94,11 @@ - (BOOL)shouldAttachGestureToSubview:(NSNumber *)handlerTag
return [[[handlerManager registry] handlerWithTag:handlerTag] wantsToAttachDirectlyToView];
}

- (void)addSubview:(UIView *)view
- (void)didAddSubview:(UIView *)view
{
[super addSubview:view];
[super didAddSubview:view];

[self tryAttachHandlerToChildView];
[self tryAttachNativeHandlersToChildView];
}

- (void)willRemoveSubview:(UIView *)subview
Expand Down Expand Up @@ -152,7 +152,7 @@ - (void)updateProps:(const Props::Shared &)propsBase oldProps:(const Props::Shar

if (handlerChange.second == RNGestureHandlerMutationAttach) {
if ([self shouldAttachGestureToSubview:handlerTag]) {
[_nativeHandlersToAttach addObject:handlerTag];
[_nativeHandlers addObject:handlerTag];
} else {
[handlerManager.registry attachHandlerWithTag:handlerTag
toView:self
Expand All @@ -163,40 +163,38 @@ - (void)updateProps:(const Props::Shared &)propsBase oldProps:(const Props::Shar
} else if (handlerChange.second == RNGestureHandlerMutationDetach) {
[handlerManager.registry detachHandlerWithTag:handlerTag];
[_attachedHandlers removeObject:handlerTag];
[_nativeHandlers removeObject:handlerTag];
}

[self tryAttachHandlerToChildView];
}
[self tryAttachNativeHandlersToChildView];

[super updateProps:propsBase oldProps:oldPropsBase];
// Override to force hittesting to work outside bounds
self.clipsToBounds = NO;
}

- (void)tryAttachHandlerToChildView
- (void)tryAttachNativeHandlersToChildView
{
if (!self.subviews[0])
return;
Comment on lines +178 to +179
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but this should never happen with NativeHandler and if it does, I believe we would like to throw an error instead of silent fail.

RNGestureHandlerManager *handlerManager = [RNGestureHandlerModule handlerManagerForModuleId:_moduleId];

for (NSNumber *handlerTag in _nativeHandlersToAttach) {
for (NSNumber *handlerTag in _nativeHandlers) {
[handlerManager.registry attachHandlerWithTag:handlerTag
toView:self.subviews[0]
withActionType:RNGestureHandlerActionTypeNativeDetector];

[_attachedHandlers addObject:handlerTag];
}

[_nativeHandlersToAttach removeAllObjects];
}

- (void)detachNativeGestureHandlers
{
RNGestureHandlerManager *handlerManager = [RNGestureHandlerModule handlerManagerForModuleId:_moduleId];

for (NSNumber *handlerTag in _attachedHandlers) {
if ([self shouldAttachGestureToSubview:handlerTag]) {
[[handlerManager registry] detachHandlerWithTag:handlerTag];
[_attachedHandlers removeObject:handlerTag];
}
for (NSNumber *handlerTag in _nativeHandlers) {
[[handlerManager registry] detachHandlerWithTag:handlerTag];
[_attachedHandlers removeObject:handlerTag];
}
}

Expand Down
Loading