@@ -140,6 +140,21 @@ - (void)initCommonProps
140
140
[_controller setViewControllers: @[ [UIViewController new ] ]];
141
141
}
142
142
143
+ #pragma mark - helper methods
144
+
145
+ - (BOOL )shouldCancelDismissFromView : (RNSScreenView *)fromView toView : (RNSScreenView *)toView
146
+ {
147
+ int fromIndex = (int )[_reactSubviews indexOfObject: fromView];
148
+ int toIndex = (int )[_reactSubviews indexOfObject: toView];
149
+ for (int i = fromIndex; i > toIndex; i--) {
150
+ if (_reactSubviews[i].preventNativeDismiss ) {
151
+ return YES ;
152
+ break ;
153
+ }
154
+ }
155
+ return NO ;
156
+ }
157
+
143
158
#pragma mark - Common
144
159
145
160
- (void )emitOnFinishTransitioningEvent
@@ -566,10 +581,14 @@ - (void)dismissOnReload
566
581
} else if (operation == UINavigationControllerOperationPop) {
567
582
screen = ((RNSScreen *)fromVC).screenView ;
568
583
}
584
+ BOOL shouldCancelDismiss = [self shouldCancelDismissFromView: (RNSScreenView *)fromVC.view
585
+ toView: (RNSScreenView *)toVC.view];
569
586
if (screen != nil &&
570
- // we need to return the animator when full width swiping even if the animation is not custom,
587
+ // when preventing the native dismiss with back button, we have to return the animator.
588
+ // Also, we need to return the animator when full width swiping even if the animation is not custom,
571
589
// otherwise the screen will be just popped immediately due to no animation
572
- (_isFullWidthSwiping || [RNSScreenStackAnimator isCustomAnimation: screen.stackAnimation])) {
590
+ ((operation == UINavigationControllerOperationPop && shouldCancelDismiss) || _isFullWidthSwiping ||
591
+ [RNSScreenStackAnimator isCustomAnimation: screen.stackAnimation])) {
573
592
return [[RNSScreenStackAnimator alloc ] initWithOperation: operation];
574
593
}
575
594
return nil ;
@@ -727,6 +746,26 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer
727
746
interactionControllerForAnimationController :
728
747
(id <UIViewControllerAnimatedTransitioning>)animationController
729
748
{
749
+ RNSScreenView *fromView = [_controller.transitionCoordinator viewForKey: UITransitionContextFromViewKey];
750
+ RNSScreenView *toView = [_controller.transitionCoordinator viewForKey: UITransitionContextToViewKey];
751
+ // we can intercept clicking back button here, we check reactSuperview since this method also fires when
752
+ // navigating back from JS
753
+ if (_interactionController == nil && fromView.reactSuperview ) {
754
+ BOOL shouldCancelDismiss = [self shouldCancelDismissFromView: fromView toView: toView];
755
+ if (shouldCancelDismiss) {
756
+ _interactionController = [UIPercentDrivenInteractiveTransition new ];
757
+ dispatch_after (dispatch_time (DISPATCH_TIME_NOW, (int64_t )(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue (), ^{
758
+ [self ->_interactionController cancelInteractiveTransition ];
759
+ self->_interactionController = nil ;
760
+ int fromIndex = (int )[self ->_reactSubviews indexOfObject: fromView];
761
+ int toIndex = (int )[self ->_reactSubviews indexOfObject: toView];
762
+ int indexDiff = fromIndex - toIndex;
763
+ int dismissCount = indexDiff > 0 ? indexDiff : 1 ;
764
+ [self updateContainer ];
765
+ [fromView notifyDismissCancelledWithDismissCount: dismissCount];
766
+ });
767
+ }
768
+ }
730
769
return _interactionController;
731
770
}
732
771
0 commit comments