From d32463ee83a098267315b7451defb6b4f95a8741 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 23 Jan 2020 19:19:38 -0500 Subject: [PATCH] =?UTF-8?q?Move=20gestureEnabled=20config=20to=20screen=20?= =?UTF-8?q?instead=20of=20heade=E2=80=A6=20(#254)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When you have 2 screens in a stack with the bottom one with gestureEnabled=false using the back gesture causes the screen to become unresponsive. This seems to be caused by setting interactivePopGestureRecognizer.enabled = NO as soon as the gesture starts. This causes the gesture to cancel immediately and leaves the screen in an unresponsive state. To fix this instead of using interactivePopGestureRecognizer.enabled we can leverage the existing delegate that we have in RNScreenStack. In gestureRecognizerShouldBegin we can check if the top screen has gestures enabled. To make this simpler I moved the gestureEnabled config to Screen instead of HeaderConfig. I think it also makes more sense conceptually since the gesture is tied to the screen and not the header. It also simplifies the android code a bit. This is a breaking change. Update This now only moves the config to screen since a separate fix was merged for the bug. --- .../src/main/java/com/swmansion/rnscreens/Screen.java | 9 +++++++++ .../com/swmansion/rnscreens/ScreenStackFragment.java | 6 +----- .../swmansion/rnscreens/ScreenStackHeaderConfig.java | 9 --------- .../rnscreens/ScreenStackHeaderConfigViewManager.java | 5 ----- .../com/swmansion/rnscreens/ScreenViewManager.java | 5 +++++ createNativeStackNavigator.js | 2 +- ios/RNSScreen.h | 1 + ios/RNSScreen.m | 2 ++ ios/RNSScreenStack.m | 11 ++--------- ios/RNSScreenStackHeaderConfig.h | 1 - ios/RNSScreenStackHeaderConfig.m | 4 +--- 11 files changed, 22 insertions(+), 33 deletions(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/Screen.java b/android/src/main/java/com/swmansion/rnscreens/Screen.java index 9c9074c7..a1011571 100644 --- a/android/src/main/java/com/swmansion/rnscreens/Screen.java +++ b/android/src/main/java/com/swmansion/rnscreens/Screen.java @@ -52,6 +52,7 @@ public class Screen extends ViewGroup implements ReactPointerEventsView { private boolean mTransitioning; private StackPresentation mStackPresentation = StackPresentation.PUSH; private StackAnimation mStackAnimation = StackAnimation.DEFAULT; + private boolean mGestureEnabled = true; public Screen(ReactContext context) { super(context); @@ -122,6 +123,10 @@ public class Screen extends ViewGroup implements ReactPointerEventsView { mStackAnimation = stackAnimation; } + public void setGestureEnabled(boolean gestureEnabled) { + mGestureEnabled = gestureEnabled; + } + public StackAnimation getStackAnimation() { return mStackAnimation; } @@ -169,4 +174,8 @@ public class Screen extends ViewGroup implements ReactPointerEventsView { public boolean isActive() { return mActive; } + + public boolean isGestureEnabled() { + return mGestureEnabled; + } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java index 32cb92b9..aa2785d9 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java @@ -97,10 +97,6 @@ public class ScreenStackFragment extends ScreenFragment { } public boolean isDismissable() { - View child = mScreenView.getChildAt(0); - if (child instanceof ScreenStackHeaderConfig) { - return ((ScreenStackHeaderConfig) child).isDismissable(); - } - return true; + return mScreenView.isGestureEnabled(); } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java index 7fd28394..8607aec3 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java @@ -30,7 +30,6 @@ public class ScreenStackHeaderConfig extends ViewGroup { private float mTitleFontSize; private int mBackgroundColor; private boolean mIsHidden; - private boolean mGestureEnabled = true; private boolean mIsBackButtonHidden; private boolean mIsShadowHidden; private boolean mDestroyed; @@ -115,10 +114,6 @@ public class ScreenStackHeaderConfig extends ViewGroup { return null; } - public boolean isDismissable() { - return mGestureEnabled; - } - public void onUpdate() { Screen parent = (Screen) getParent(); final ScreenStack stack = getScreenStack(); @@ -303,10 +298,6 @@ public class ScreenStackHeaderConfig extends ViewGroup { mIsShadowHidden = hideShadow; } - public void setGestureEnabled(boolean gestureEnabled) { - mGestureEnabled = gestureEnabled; - } - public void setHideBackButton(boolean hideBackButton) { mIsBackButtonHidden = hideBackButton; } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java index 7ba8f26c..1a56d1f6 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java @@ -99,11 +99,6 @@ public class ScreenStackHeaderConfigViewManager extends ViewGroupManager { } } + @ReactProp(name = "gestureEnabled", defaultBoolean = true) + public void setGestureEnabled(Screen view, boolean gestureEnabled) { + view.setGestureEnabled(gestureEnabled); + } + @Nullable @Override public Map getExportedCustomDirectEventTypeConstants() { diff --git a/createNativeStackNavigator.js b/createNativeStackNavigator.js index 1552a2f7..b9846620 100644 --- a/createNativeStackNavigator.js +++ b/createNativeStackNavigator.js @@ -75,7 +75,6 @@ class StackView extends React.Component { headerBackTitleStyle && headerBackTitleStyle.fontFamily, backTitleFontSize: headerBackTitleStyle && headerBackTitleStyle.fontSize, color: headerTintColor, - gestureEnabled: gestureEnabled === undefined ? true : gestureEnabled, largeTitle, largeTitleFontFamily: headerLargeTitleStyle && headerLargeTitleStyle.fontFamily, @@ -191,6 +190,7 @@ class StackView extends React.Component { style={options.cardStyle} stackAnimation={stackAnimation} stackPresentation={stackPresentation} + gestureEnabled={gestureEnabled === undefined ? true : gestureEnabled} onAppear={() => this._onSceneFocus(route, descriptor)} onDismissed={() => this._removeScene(route)}> {this._renderHeaderConfig(index, route, descriptor)} diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 26dbe17f..eea3ea44 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -44,6 +44,7 @@ typedef NS_ENUM(NSInteger, RNSScreenStackAnimation) { @property (weak, nonatomic) UIView *reactSuperview; @property (nonatomic, retain) UIViewController *controller; @property (nonatomic) BOOL active; +@property (nonatomic) BOOL gestureEnabled; @property (nonatomic) RNSScreenStackAnimation stackAnimation; @property (nonatomic) RNSScreenStackPresentation stackPresentation; diff --git a/ios/RNSScreen.m b/ios/RNSScreen.m index 2eaa6a06..d180a378 100644 --- a/ios/RNSScreen.m +++ b/ios/RNSScreen.m @@ -26,6 +26,7 @@ _controller = [[RNSScreen alloc] initWithView:self]; _stackPresentation = RNSScreenStackPresentationPush; _stackAnimation = RNSScreenStackAnimationDefault; + _gestureEnabled = YES; } return self; @@ -276,6 +277,7 @@ RCT_EXPORT_MODULE() RCT_EXPORT_VIEW_PROPERTY(active, BOOL) +RCT_EXPORT_VIEW_PROPERTY(gestureEnabled, BOOL) RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation) RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation) RCT_EXPORT_VIEW_PROPERTY(onAppear, RCTDirectEventBlock); diff --git a/ios/RNSScreenStack.m b/ios/RNSScreenStack.m index 3f807e13..5fcdbce1 100644 --- a/ios/RNSScreenStack.m +++ b/ios/RNSScreenStack.m @@ -102,16 +102,9 @@ RCTRootContentView *rootView = (RCTRootContentView *)parent; [rootView.touchHandler cancel]; - UIView *topView = _controller.viewControllers.lastObject.view; - RNSScreenStackHeaderConfig *config = nil; - for (UIView *subview in topView.reactSubviews) { - if ([subview isKindOfClass:[RNSScreenStackHeaderConfig class]]) { - config = (RNSScreenStackHeaderConfig*) subview; - break; - } - } + RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; - return _controller.viewControllers.count > 1 && (config == nil || config.gestureEnabled); + return _controller.viewControllers.count > 1 && topScreen.gestureEnabled; } - (void)markChildUpdated diff --git a/ios/RNSScreenStackHeaderConfig.h b/ios/RNSScreenStackHeaderConfig.h index b99d963b..89fcf39a 100644 --- a/ios/RNSScreenStackHeaderConfig.h +++ b/ios/RNSScreenStackHeaderConfig.h @@ -23,7 +23,6 @@ @property (nonatomic) BOOL hideBackButton; @property (nonatomic) BOOL hideShadow; @property (nonatomic) BOOL translucent; -@property (nonatomic) BOOL gestureEnabled; + (void)willShowViewController:(UIViewController *)vc withConfig:(RNSScreenStackHeaderConfig*)config; diff --git a/ios/RNSScreenStackHeaderConfig.m b/ios/RNSScreenStackHeaderConfig.m index 9c918f70..e8488567 100644 --- a/ios/RNSScreenStackHeaderConfig.m +++ b/ios/RNSScreenStackHeaderConfig.m @@ -60,7 +60,6 @@ self.hidden = YES; _translucent = YES; _reactSubviews = [NSMutableArray new]; - _gestureEnabled = YES; } return self; } @@ -269,7 +268,7 @@ [navctr setNavigationBarHidden:shouldHide animated:YES]; #ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { - vc.modalInPresentation = !config.gestureEnabled; + vc.modalInPresentation = !config.screenView.gestureEnabled; } #endif if (shouldHide) { @@ -454,7 +453,6 @@ RCT_EXPORT_VIEW_PROPERTY(hideShadow, BOOL) // `hidden` is an UIView property, we need to use different name internally RCT_REMAP_VIEW_PROPERTY(hidden, hide, BOOL) RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL) -RCT_EXPORT_VIEW_PROPERTY(gestureEnabled, BOOL) @end