diff --git a/ios/TrueSheetViewController.mm b/ios/TrueSheetViewController.mm index 74471b93..797e3e93 100644 --- a/ios/TrueSheetViewController.mm +++ b/ios/TrueSheetViewController.mm @@ -242,6 +242,10 @@ - (void)viewDidAppear:(BOOL)animated { [self setupGestureRecognizer]; _isPresented = YES; + } else { + // Re-attach gesture handlers that were cleaned up in viewWillDisappear + // (e.g. when a child sheet was presented on top and is now dismissed) + [self setupGestureRecognizer]; } } @@ -274,6 +278,10 @@ - (void)emitDidDismissEvents { - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; + // Remove gesture handler targets before the view disappears to prevent + // orphaned handlers from blocking scroll on the presenting view controller. + [self cleanupGestureRecognizer]; + // Dispatch to allow pan gesture to set _isDragging before checking // handleTransitionTracker will emit when sheet is transitioning to dismiss dispatch_async(dispatch_get_main_queue(), ^{ @@ -377,6 +385,24 @@ - (void)setupGestureRecognizer { } } +- (void)cleanupGestureRecognizer { + UIView *presentedView = self.presentedView; + if (!presentedView) + return; + + [GestureUtil detachPanGestureHandler:presentedView target:self selector:@selector(handlePanGesture:)]; + + TrueSheetContentView *contentView = [self findContentView:presentedView]; + if (contentView) { + RCTScrollViewComponentView *scrollViewComponent = [contentView findScrollView]; + if (scrollViewComponent && scrollViewComponent.scrollView) { + [GestureUtil detachPanGestureHandler:scrollViewComponent.scrollView + target:self + selector:@selector(handlePanGesture:)]; + } + } +} + - (void)setupDraggable { UIView *presentedView = self.presentedView; if (!presentedView) diff --git a/ios/utils/GestureUtil.h b/ios/utils/GestureUtil.h index 89196898..04c16c87 100644 --- a/ios/utils/GestureUtil.h +++ b/ios/utils/GestureUtil.h @@ -20,6 +20,14 @@ NS_ASSUME_NONNULL_BEGIN */ + (void)attachPanGestureHandler:(UIView *)view target:(id)target selector:(SEL)selector; +/** + * Detaches a pan gesture handler from all pan gesture recognizers on a view + * @param view The view whose pan gesture recognizers to detach from + * @param target The target object to remove + * @param selector The selector to remove + */ ++ (void)detachPanGestureHandler:(UIView *)view target:(id)target selector:(SEL)selector; + /** * Enables or disables all pan gesture recognizers on a view * @param view The view whose pan gesture recognizers to enable/disable diff --git a/ios/utils/GestureUtil.mm b/ios/utils/GestureUtil.mm index 5a9ad110..78b93079 100644 --- a/ios/utils/GestureUtil.mm +++ b/ios/utils/GestureUtil.mm @@ -23,6 +23,19 @@ + (void)attachPanGestureHandler:(UIView *)view target:(id)target selector:(SEL)s } } ++ (void)detachPanGestureHandler:(UIView *)view target:(id)target selector:(SEL)selector { + if (!view || !target || !selector) { + return; + } + + for (UIGestureRecognizer *recognizer in view.gestureRecognizers ?: @[]) { + if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) { + UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)recognizer; + [panGesture removeTarget:target action:selector]; + } + } +} + + (void)setPanGesturesEnabled:(BOOL)enabled forView:(UIView *)view { if (!view) { return;