iOS 实现滑动和点击返回的事件拦截

637 阅读1分钟

自定义的导航栏控制器

  • 先创建一个自定义的导航栏控制器
@interface ZNNavViewController : UINavigationController

@end
  • 遵循下面两个协议,并设置代理为导航栏控制器
@interface ZNNavViewController ()<UINavigationBarDelegate, UIGestureRecognizerDelegate>

@end

@implementation ZNNavViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // 设置代理
    self.navigationBar.delegate = self;
    self.interactivePopGestureRecognizer.delegate = self;
}

@end
  • 创建响应返回事件的代理方法
// 可以直接写的到自定义导航栏控制器的他头文件里面
@protocol NavbarBackButtonHandlerProtocol <NSObject>
@optional
// 重写下面的方法以拦截导航栏返回按钮点击事件,返回 YES 则 pop,NO 则不 pop
- (BOOL)zn_navigationBarShouldPopWhenBackButtonClick;
- (BOOL)zn_gestureRecognizerShouldBegin;
@end

@interface UIViewController (BackButtonHandler) <NavbarBackButtonHandlerProtocol>

@end
  • 实现代理方法

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.navigationBar.delegate = self;
    self.interactivePopGestureRecognizer.delegate = self;
}

// 这个是滑动返回的代理方法
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    BOOL shouldPop = YES;
    UIViewController* vc = [self topViewController];
    if([vc respondsToSelector:@selector(zn_gestureRecognizerShouldBegin)])
    {
        shouldPop = [vc zn_gestureRecognizerShouldBegin];
    }
    return shouldPop;
}

// 这个是点击返回的代理发狠啊
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
    if([self.viewControllers count] < [navigationBar.items count]) {
        return YES;
    }

    BOOL shouldPop = YES;
    UIViewController* vc = [self topViewController];
    if([vc respondsToSelector:@selector(zn_navigationBarShouldPopWhenBackButtonClick)])
    {
        shouldPop = [vc zn_navigationBarShouldPopWhenBackButtonClick];
    }

    if(shouldPop)
    {
        [self popViewControllerAnimated:YES];
    }
    
    return NO;
}

使用

  • 在当前需要监听返回的控制器中实现代理方法即可
/// MARK: - Views
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

/// MARK: - Events button click
- (BOOL)zn_gestureRecognizerShouldBegin
{
    if (self.textView.text.length == 0) {
        return NO;
    }
    if ([self.saveButton.title isEqualToString:@"Text_VC_Sheet_Edit"]) {
        return YES;
    }
    
    return NO;
}
- (BOOL)zn_navigationBarShouldPopWhenBackButtonClick
{
    if (self.textView.text.length == 0) {
        return NO;
    }
    if ([self.saveButton.title isEqualToString:@"Text_VC_Sheet_Edit"]) {
        return YES;
    }
    
    return NO;
}

自定义导航栏控制器全部代码

  • .h文件
@protocol NavbarBackButtonHandlerProtocol <NSObject>
@optional
// 重写下面的方法以拦截导航栏返回按钮点击事件,返回 YES 则 pop,NO 则不 pop
- (BOOL)zn_navigationBarShouldPopWhenBackButtonClick;
- (BOOL)zn_gestureRecognizerShouldBegin;
@end

@interface UIViewController (BackButtonHandler) <NavbarBackButtonHandlerProtocol>

@end

@interface ZNNavViewController : UINavigationController

@end

  • .m 文件

#import "ZNNavViewController.h"


@implementation UIViewController (BackButtonHandler)

@end

@interface ZNNavViewController ()<UINavigationBarDelegate, UIGestureRecognizerDelegate>

@end

@implementation ZNNavViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.navigationBar.delegate = self;
    self.interactivePopGestureRecognizer.delegate = self;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    BOOL shouldPop = YES;
    UIViewController* vc = [self topViewController];
    if([vc respondsToSelector:@selector(zn_gestureRecognizerShouldBegin)])
    {
        shouldPop = [vc zn_gestureRecognizerShouldBegin];
    }
    return shouldPop;
}

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
    if([self.viewControllers count] < [navigationBar.items count]) {
        return YES;
    }

    BOOL shouldPop = YES;
    UIViewController* vc = [self topViewController];
    if([vc respondsToSelector:@selector(zn_navigationBarShouldPopWhenBackButtonClick)])
    {
        shouldPop = [vc zn_navigationBarShouldPopWhenBackButtonClick];
    }

    if(shouldPop)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self popViewControllerAnimated:YES];
        });
    }
    
    return NO;
}

@end