NavigatorIOS: Expose interactivePopGestureEnabled property
Summary: Previously, the back swipe navigation gesture would be enabled when the navigation bar is shown and disabled when the navigation bar is hidden. This change enables developers to control the back swipe gesture independently of the visibility of the navigation bar. An example use case would be that an app wants to render a custom navigation bar so it sets `navigationBarHidden` to true and it wants to enable the back swipe gesture so it sets `interactivePopGestureEnabled` to true. **Test plan (required)** - Created a test app to verify setting `interactivePopGestureEnabled` to `true` and `false` with the navigation bar both hidden and shown. - Verified prop works in a larger app. Adam Comella Microsoft Corp. Closes https://github.com/facebook/react-native/pull/7369 Differential Revision: D3269304 Pulled By: javache fb-gh-sync-id: ec4324f6517cec4b4fc4f62c4394dc9208a8af6a fbshipit-source-id: ec4324f6517cec4b4fc4f62c4394dc9208a8af6a
This commit is contained in:
parent
2132ad1441
commit
4d2c72b977
|
@ -308,6 +308,15 @@ var NavigatorIOS = React.createClass({
|
|||
*/
|
||||
translucent: PropTypes.bool,
|
||||
|
||||
/**
|
||||
* A Boolean value that indicates whether the interactive pop gesture is enabled. Useful
|
||||
* for enabling/disabling the back swipe navigation gesture. If this prop is not provided,
|
||||
* the default behavior is for the back swipe gesture to be enabled when the navigation bar
|
||||
* is shown and disabled when the navigation bar is hidden. Once you've provided
|
||||
* the interactivePopGestureEnabled prop, you can never restore the default behavior.
|
||||
*/
|
||||
interactivePopGestureEnabled: PropTypes.bool,
|
||||
|
||||
},
|
||||
|
||||
navigator: (undefined: ?Object),
|
||||
|
@ -686,7 +695,8 @@ var NavigatorIOS = React.createClass({
|
|||
style={styles.transitioner}
|
||||
vertical={this.props.vertical}
|
||||
requestedTopOfStack={this.state.requestedTopOfStack}
|
||||
onNavigationComplete={this._handleNavigationComplete}>
|
||||
onNavigationComplete={this._handleNavigationComplete}
|
||||
interactivePopGestureEnabled={this.props.interactivePopGestureEnabled}>
|
||||
{items}
|
||||
</NavigatorTransitionerIOS>
|
||||
</StaticContainer>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
@property (nonatomic, strong) UIView *reactNavSuperviewLink;
|
||||
@property (nonatomic, assign) NSInteger requestedTopOfStack;
|
||||
@property (nonatomic, assign) BOOL interactivePopGestureEnabled;
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
|
|
@ -27,6 +27,20 @@ typedef NS_ENUM(NSUInteger, RCTNavigationLock) {
|
|||
RCTNavigationLockJavaScript
|
||||
};
|
||||
|
||||
// By default the interactive pop gesture will be enabled when the navigation bar is displayed
|
||||
// and disabled when hidden
|
||||
// RCTPopGestureStateDefault maps to the default behavior (mentioned above). Once popGestureState
|
||||
// leaves this value, it can never be returned back to it. This is because, due to a limitation in
|
||||
// the iOS APIs, once we override the default behavior of the gesture recognizer, we cannot return
|
||||
// back to it.
|
||||
// RCTPopGestureStateEnabled will enable the gesture independent of nav bar visibility
|
||||
// RCTPopGestureStateDisabled will disable the gesture independent of nav bar visibility
|
||||
typedef NS_ENUM(NSUInteger, RCTPopGestureState) {
|
||||
RCTPopGestureStateDefault = 0,
|
||||
RCTPopGestureStateEnabled,
|
||||
RCTPopGestureStateDisabled
|
||||
};
|
||||
|
||||
NSInteger kNeverRequested = -1;
|
||||
NSInteger kNeverProgressed = -10000;
|
||||
|
||||
|
@ -191,13 +205,15 @@ NSInteger kNeverProgressed = -10000;
|
|||
|
||||
@end
|
||||
|
||||
@interface RCTNavigator() <RCTWrapperViewControllerNavigationListener, UINavigationControllerDelegate>
|
||||
@interface RCTNavigator() <RCTWrapperViewControllerNavigationListener, UINavigationControllerDelegate, UIGestureRecognizerDelegate>
|
||||
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onNavigationProgress;
|
||||
@property (nonatomic, copy) RCTBubblingEventBlock onNavigationComplete;
|
||||
|
||||
@property (nonatomic, assign) NSInteger previousRequestedTopOfStack;
|
||||
|
||||
@property (nonatomic, assign) RCTPopGestureState popGestureState;
|
||||
|
||||
// Previous views are only mainted in order to detect incorrect
|
||||
// addition/removal of views below the `requestedTopOfStack`
|
||||
@property (nonatomic, copy, readwrite) NSArray<RCTNavItem *> *previousViews;
|
||||
|
@ -332,8 +348,21 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setInteractivePopGestureEnabled:(BOOL)interactivePopGestureEnabled
|
||||
{
|
||||
_interactivePopGestureEnabled = interactivePopGestureEnabled;
|
||||
|
||||
_navigationController.interactivePopGestureRecognizer.delegate = self;
|
||||
_navigationController.interactivePopGestureRecognizer.enabled = interactivePopGestureEnabled;
|
||||
|
||||
_popGestureState = interactivePopGestureEnabled ? RCTPopGestureStateEnabled : RCTPopGestureStateDisabled;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_navigationController.interactivePopGestureRecognizer.delegate == self) {
|
||||
_navigationController.interactivePopGestureRecognizer.delegate = nil;
|
||||
}
|
||||
_navigationController.delegate = nil;
|
||||
[_navigationController removeFromParentViewController];
|
||||
}
|
||||
|
@ -343,6 +372,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
return _navigationController;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
return _navigationController.viewControllers.count > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* See documentation about lock lifecycle. This is only here to clean up
|
||||
* swipe-back abort interaction, which leaves us *no* other way to clean up
|
||||
|
@ -399,7 +433,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
- (void)freeLock
|
||||
{
|
||||
_navigationController.navigationLock = RCTNavigationLockNone;
|
||||
_navigationController.interactivePopGestureRecognizer.enabled = YES;
|
||||
|
||||
// Unless the pop gesture has been explicitly disabled (RCTPopGestureStateDisabled),
|
||||
// Set interactivePopGestureRecognizer.enabled to YES
|
||||
// If the popGestureState is RCTPopGestureStateDefault the default behavior will be maintained
|
||||
_navigationController.interactivePopGestureRecognizer.enabled = self.popGestureState != RCTPopGestureStateDisabled;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@ RCT_EXPORT_MODULE()
|
|||
RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack, NSInteger)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onNavigationProgress, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onNavigationComplete, RCTBubblingEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(interactivePopGestureEnabled, BOOL)
|
||||
|
||||
// TODO: remove error callbacks
|
||||
RCT_EXPORT_METHOD(requestSchedulingJavaScriptNavigation:(nonnull NSNumber *)reactTag
|
||||
|
|
Loading…
Reference in New Issue