需求是從不同頁面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