带有自定义后退按钮的滑动手势冻结根视图控制器

Posted

技术标签:

【中文标题】带有自定义后退按钮的滑动手势冻结根视图控制器【英文标题】:Slide gesture with custom back button freezes the root view controller 【发布时间】:2014-02-26 19:30:38 【问题描述】:

我的应用程序中都有自定义后退按钮,看起来导航控制器不喜欢它。

所以,我希望 ios7 滑动返回手势与我的自定义返回按钮一起使用。搜索并尝试了不同的方法,但似乎都没有希望。我能得到的最接近的是http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/。 但是,现在当我继续推送和弹出导航堆栈时,堆栈中的 rootViewController 会停止响应任何触摸。

有什么建议吗?

【问题讨论】:

那个链接失效了? 【参考方案1】:

继承 UINavigationController,就像 keighl 建议的那样,是 imo 的正确方法。但是他错过了对根视图控制器的检查,以避免在根视图上执行手势时冻结。 这是带有附加检查的修改版本:

CBNavigationController.h:

#import <UIKit/UIKit.h>

@interface CBNavigationController : UINavigationController <UIGestureRecognizerDelegate, UINavigationControllerDelegate>
@end

CBNavigationController.m:

#import "CBNavigationController.h"

@interface CBNavigationController ()
@end

@implementation CBNavigationController
- (void)viewDidLoad

    NSLog(@"%s",__FUNCTION__);
    __weak CBNavigationController *weakSelf = self;

    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
    
        self.interactivePopGestureRecognizer.delegate = weakSelf;
        self.delegate = weakSelf;
    


- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated

    NSLog(@"%s",__FUNCTION__);

    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
        self.interactivePopGestureRecognizer.enabled = NO;

    [super pushViewController:viewController animated:animated];


#pragma mark UINavigationControllerDelegate

- (void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animate

    NSLog(@"%s",__FUNCTION__);

    // Enable the gesture again once the new controller is shown AND is not the root view controller
    if (viewController == self.viewControllers.firstObject)
    
        if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
            self.interactivePopGestureRecognizer.enabled = NO;
    
    else
    
        if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
            self.interactivePopGestureRecognizer.enabled = YES;
    


@end

objective-c

【讨论】:

这应该被标记为正确答案 - 只有一个适用于所有情况。【参考方案2】:

我遇到了同样的问题,这是我的解决方案: 在您的自定义 NavigationController 中,例如 MYNavigationController,因为您将手势委托设置为 navigationController,您可以在其中添加委托方法:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    if (self.viewControllers.count>1) 
        return YES;
    
    return NO;
然后它将在根视图控制器中停止弹出动作并避免冻结行为。

【讨论】:

那行不通——当你在动画发生时继续滑动仍然会导致卡顿【参考方案3】:

即使我遇到了同样的问题,我也已通过修改您所指链接中提供的代码来解决它。现在我的屏幕很少冻结,但仍然无法找到永久修复。

@implementation PPNavigationController

-(void)viewDidLoad

    //[super viewDidLoad];
    // Do any additional setup after loading the view.

     __weak PPNavigationController *weakSelf = self;

    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
    
        self.interactivePopGestureRecognizer.delegate = weakSelf;
        self.delegate = weakSelf;
    





-(void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animate

    // Enable the gesture again once the new controller is shown

    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
        self.interactivePopGestureRecognizer.delegate = viewController;


Don't use this method
//-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
//

【讨论】:

嘿阿南德,我之前已经尝试过上面的代码,它确实使情况好一些。但是当你从导航堆栈中推送和弹出很多时,屏幕仍然会冻结。【参考方案4】:

这是我对here提出的类似问题的回答

您可以使用一些小技巧来让本机手势正常工作。 创建UINavigationItem的子类,然后重写leftBarButtonItems方法:

- (NSArray*)leftBarButtonItems

    return nil;

现在将此类用于具有自定义左侧UIBarButtonItem 的项目。手势有效!这是因为UINavigationController 认为没有剩余项目并启用手势。您仍然可以通过 leftBarButtonItem 属性访问您的自定义项。

【讨论】:

【参考方案5】:

这是UINavigationController 的一个简单的Swift 子类,您可以使用我改编自@weak 的答案。不需要实现 UIGestureRecognizerDelegate,因为导航代理的 navigationController(_:didShow:animated:) 处理启用和禁用弹出手势的工作。

在故事板或代码中使用此子类比在嵌入在导航控制器中的其他控制器中一次性禁用更容易。

import UIKit

@objc class LWNavigationController : UINavigationController,
                                     UINavigationControllerDelegate 
    override func viewDidLoad() 
        self.delegate = self
    

    override func pushViewController(_ viewController: UIViewController,
                                     animated: Bool) 
        // Disable this gesture while animating a push.
        self.interactivePopGestureRecognizer?.isEnabled = false
        super.pushViewController(viewController, animated: animated)
        debugPrint("------\(#function) \(viewController)------")
    

    // MARK: - UINavigationControllerDelegate

    func navigationController(_ navigationController: UINavigationController,
                              didShow viewController: UIViewController,
                              animated: Bool) 
        if (viewController == self.viewControllers.first) 
            // Keep the gesture disabled if we're at the root to avoid back swipes
            // from corrupting the navigation stack.
            self.interactivePopGestureRecognizer?.isEnabled = false
         else 
            self.interactivePopGestureRecognizer?.isEnabled = true
        
        debugPrint("------\(#function) \(viewController) " +
                   "enabled: \(self.interactivePopGestureRecognizer?.isEnabled)" +
                   "------")
    

【讨论】:

以上是关于带有自定义后退按钮的滑动手势冻结根视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - navigationBarBackButtonHidden - 向后滑动手势?

带有自定义后退按钮字体的错误大标题动画

带有自定义后退导航按钮的自定义按钮栏

如何使用 UIGestureRecognizer 交换视图

使用自定义字体时,UIBarButtonItem 在后退手势上跳转

iOS 自定义返回按钮,保留系统滑动返回