在 iOS 7 中,Apple 添加了新的默认导航行为。您可以从屏幕的左边缘滑动以返回导航堆栈。但在我的应用程序中,这种行为与我的自定义左侧菜单冲突。那么,是否可以在 UINavigationController 中禁用这个新手势?
navigationItem.hidesBackButton = true
,此手势也会被禁用。在我的情况下,我实现了一个自定义后退按钮并添加为 leftBarButtonItem
我找到了一个解决方案:
目标-C:
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Swift 3+:
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
我发现仅将手势设置为禁用并不总是有效。它确实有效,但对我来说,它只有在我使用过一次后退手势后才有效。第二次它不会触发背景手势。
对我来说,修复是委托手势并实现 shouldbegin 方法以返回 NO:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Disable iOS 7 back gesture
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Enable iOS 7 back gesture
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return NO;
}
viewWillAppear
。由于当前视图仍处于活动状态,这可能会导致代码逻辑严重受损。可能是你崩溃的原因。
enabled
是/否行?您从 gestureRecognizerShouldBegin
返回 NO
,这还不够吗?
self.navigationController.navigationController
执行相同操作。请参阅stackoverflow.com/a/50012503/5605365
只需从 NavigationController 中删除手势识别器。在 iOS 8 中工作。
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
[self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];
[self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer]
。
从 iOS 8 开始,接受的答案不再有效。我需要在我的主游戏屏幕上停止滑动以关闭手势,所以实现了这个:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return NO;
}
我已经完善了 Twan 的答案,因为:
当您返回根视图控制器并在导航到其他位置之前做出滑动手势时,您的视图控制器可能被设置为其他手势识别器的委托,将委托设置为 nil 会导致挂起问题。
以下示例假设 iOS 7:
{
id savedGestureRecognizerDelegate;
}
- (void)viewWillAppear:(BOOL)animated
{
savedGestureRecognizerDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated
{
self.navigationController.interactivePopGestureRecognizer.delegate = savedGestureRecognizerDelegate;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) {
return NO;
}
// add whatever logic you would otherwise have
return YES;
}
请在root vc中设置:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:YES];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
对于斯威夫特:
navigationController!.interactivePopGestureRecognizer!.enabled = false
swift 5, swift 4.2 可以使用下面的代码。
// disable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
// enable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
它适用于 ios 10 及更高版本:
- (void)viewWillAppear:(BOOL)animated {
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
它不适用于 viewDidLoad() 方法。
编辑
如果您想管理特定导航控制器的向后滑动功能,请考虑使用 SwipeBack。
这样,您可以设置 navigationController.swipeBackEnabled = NO
。
例如:
#import <SwipeBack/SwipeBack.h>
- (void)viewWillAppear:(BOOL)animated
{
navigationController.swipeBackEnabled = NO;
}
它可以通过 CocoaPods 安装。
pod 'SwipeBack', '~> 1.0'
我为缺乏解释而道歉。
self.navigationController.swipeBackEnabled = NO
我很确定这会只禁用图书馆的向后滑动手势,但系统的滑动手势仍将启用。
我的方法。一个手势识别器来统治它们:
class DisabledGestureViewController: UIViewController: UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.interactivePopGestureRecognizer!.delegate = self
}
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
// Prevent going back to the previous view
return !(navigationController!.topViewController is DisabledGestureViewController)
}
}
重要提示:不要在导航堆栈中的任何位置重置委托:navigationController!.interactivePopGestureRecognizer!.delegate = nil
这是 Swift 3 的方式
为我工作
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
所有这些解决方案都以他们不推荐的方式操纵 Apple 的手势识别器。我刚刚被一个朋友告诉我有一个更好的解决方案:
[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];
其中 myPanGestureRecognizer 是您用来显示菜单的手势识别器。这样,当您按下新的导航控制器时,Apple 的手势识别器不会被他们重新打开,并且您无需依赖在手机进入睡眠状态或负载过重时可能会过早触发的 hacky 延迟。
把它留在这里是因为我知道下次我需要它时我不会记住它,然后我会在这里找到问题的解决方案。
给出的答案都没有帮助我解决问题。在这里发布我的答案;可能对某人有帮助
在视图控制器中将 private var popGesture: UIGestureRecognizer?
声明为全局变量。然后在 viewDidAppear 和 viewWillDisappear 方法中实现代码
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if self.navigationController!.respondsToSelector(Selector("interactivePopGestureRecognizer")) {
self.popGesture = navigationController!.interactivePopGestureRecognizer
self.navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer!)
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.popGesture != nil {
navigationController!.view.addGestureRecognizer(self.popGesture!)
}
}
这将在 iOS v8.x 及更高版本中禁用滑动
interactivePopGestureRecognizer.delegate
。
if( .. respondsToSelector ..
。下一行将 popGesture 设置为识别器或 nil。然后使用它的值:if (self.popGesture != nil) self.navigationController .. removeGestureRecognizer( self.popGesture )
。
这适用于 iOS 8 的 viewDidLoad:
:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.navigationController.interactivePopGestureRecognizer.enabled = false;
});
很多问题都可以在优秀的 ol' dispatch_after
的帮助下得到解决。
尽管请注意此解决方案可能不安全,但请使用您自己的推理。
更新
对于 iOS 8.1 延迟时间应为 0.5 秒
在 iOS 9.3 上不再需要延迟,只需将其放在 viewDidLoad
中即可工作:
(待定,如果在 iOS 9.0-9.3 上工作)
navigationController?.interactivePopGestureRecognizer?.enabled = false
viewDidLoad
加上延迟是一种冒险的编程做法。一个坏习惯开始。如果用户在您的延迟通话开始之前开始滑动怎么办?没有安全时间可以保证足够长但不会太长。这就是为什么早在您之前发布的其他答案建议将代码放在 viewDidAppear
中的原因。这确保了一切都已安装。不要发明任意延迟;按预期使用 Apple 的调用顺序。
它适用于大多数视图控制器。
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
它不适用于像 UIPageViewController 这样的视图控制器。在 UIPageViewController 的 pagecontentviewcontroller 上,下面的代码对我有用。
override func viewDidLoad() {
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
}
在 UIGestureRecognizerDelegate 上,
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
return false
}
return true
}
对于 Swift 4 这有效:
class MyViewController: UIViewController, UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.interactivePopGestureRecognizer?.gesture.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.navigationController?.interactivePopGestureRecognizer?.gesture.isEnabled = false
}
}
self.navigationController.pushViewController(VC, animated: Bool)
称呼
self.navigationController.setViewContollers([VC], animated: Bool)
setViewControllers 替换堆栈上的所有 VC,而不是在顶部添加新控制器。这意味着新设置的 VC 是根 VC,用户无法返回。
当您只想禁用单个 VC 上的滑动并为其他 VC 保留滑动到背面时,这是最有效的。
如果您希望用户能够返回,而不是通过滑动,请不要使用此方法,因为它会禁用所有返回(因为没有 VC 可以返回)
viewDidAppear:
/viewDidDisappear
上enable / disable
识别器。或者,您可以使用更复杂的逻辑实现UIGestureRecognizerDelegate
协议并将其设置为recognizer.delegate
属性。self.navigationController.interactivePopGestureRecognizer.enabled
属性在以下视图的方法中不起作用:viewDidLoad
、viewWillAppear
、viewDidAppear
、viewDidDisappear
,但在方法viewWillDisappear
中起作用。在 iOS7 上,它适用于上述所有方法。因此,在处理 viewController 时尝试在任何其他方法中使用它,当我单击视图内的某个按钮时,我确认它在 iOS8 上对我有效。