需求是从不同页面push过来要做不同的pop,有的直接返回上一级,有的要返回到rootViewController。
介绍我想到的有两种方式和遇到的问题以及解决的办法。
方式一:
自定义一个按钮,添加点击事件,在事件中去自由的pop,然后把这个自定义按钮设置为导航栏的self.navigationItem.leftBarButtonItem。
存在的问题:左滑返回的手势失效了。
解决办法:
第一步:在RootViewController的viewDidAppear中把self.navigationController.interactivePopGestureRecognizer.enabled = NO;
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// 解决自定义返回按钮影响左滑手势的问题
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
第二步:
在push控制器前调用
// 解决自定义返回按钮影响左滑手势的问题
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
方式二:
但是我的项目中用的都是系统的返回按钮,如果自定义的话样式会不统一,所以要用系统的返回按钮。
存在的问题:怎么拦截导航栏返回按钮事件
解决办法
声明:此方法网上流传已久,我只是搬运工,记录下来。具体的作者我也不知道是谁,向作者致敬。@此方法的第一位分享者
可能是http://stackoverflow.com/questions/1214965/setting-action-for-back-button-in-navigation-controller/19132881#19132881
可以为 UINavigatonController 创建一个 Category,来定制navigationBar: shouldPopItem: 的逻辑。这里需要注意的是,我们不需要去设置 delegate,因为 UINavigatonController 自带的 UINavigationBar 的 delegate 就是导航栏本身。这样还有个问题就是,那在实际的 Controller 里面怎么控制呢?因此同样需要对 UIViewController 添加一个 Protocol,这样在 Controller 中使用该 Protocol 提供的方法即可进行控制了,代码如下
.h中:
@protocol BackButtonHandlerProtocol <NSObject>
@optional
// 重写下面的方法以拦截导航栏返回按钮点击事件,返回 YES 则 pop,NO 则不 pop
-(BOOL)navigationShouldPopOnBackButton;
@end
@interface UIViewController (BackButtonHandler) <BackButtonHandlerProtocol>
@end
.m中
@implementation UIViewController (BackButtonHandler)
@end
@implementation UINavigationController (ShouldPopOnBackButton)
- (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(navigationShouldPopOnBackButton)]) {
shouldPop = [vc navigationShouldPopOnBackButton];
}
if(shouldPop) {
dispatch_async(dispatch_get_main_queue(), ^{
[self popViewControllerAnimated:YES];
});
} else {
// 取消 pop 后,复原返回按钮的状态
for(UIView *subview in [navigationBar subviews]) {
if(0. < subview.alpha && subview.alpha < 1.) {
[UIView animateWithDuration:.25 animations:^{
subview.alpha = 1.;
}];
}
}
}
return NO;
}
@end
调用:
在需要定制的ViewController中导入分类
#import "UIViewController+BackButtonHandler.h"
重写navigationShouldPopOnBackButton方法:
- (void)navigationShouldPopOnBackButton {
// 定制具体的pop方式
if ([self.inputParameter[@"isAgreementPage"] boolValue]) {
[self.navigationController popToRootViewControllerAnimated:YES];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
}
@end
网友评论