iOS攔截導航欄返回按鈕事件的正確方式

當我們使用了系統的導航欄時,默認點擊返回按鈕是 pop 回上一個界面。但是在有時候,我們需要在點擊導航欄的返回按鈕時不一定要 pop 回上一界面,比如一個視頻播放界面,進入橫屏后,默認點擊返回按鈕仍然是 pop 返回上一個界面,但是如果我們想要在橫屏點擊返回按鈕的時候是返回豎屏模式,而不是 pop 到上一界面,這該怎么實現呢?

注意:我們要的不是獲取點擊返回按鈕的時機,而是想要攔截點擊返回按鈕的 pop 操作,使我們可以進行選擇性的 pop,而不是必然的 pop。

下面一步步來解決這個問題。

一、自定義返回按鈕

第一種,自定義導航欄的返回按鈕,雖然這看起來是一種方式,但是也不能從根本上解決;比如整個應用的返回鍵都是統一的,這時候再重寫了某個界面的返回按鈕感覺就不統一了。而且每有一個界面有這個需求都需要重新自定義一個返回按鈕,顯得不優雅。

自定義返回按鈕的方法很簡單,如下:

// 自定義返回按鈕
- (void)customBackButton{
    UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [backBtn setTitle:@"返回" forState:UIControlStateNormal];
    [backBtn addTarget:self action:@selector(backBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
    backBtn.frame = CGRectMake(0, 0, 60, 40);
    [backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithCustomView:backBtn];
    self.navigationItem.leftBarButtonItem = item;
}
// 返回按鈕按下
- (void)backBtnClicked:(UIButton *)sender{
    if (_isLandscape) {
        // 進入豎屏
        [self enterPortrait];   
        return;
    }
    // pop
    [self.navigationController popViewControllerAnimated:YES];
}

二、為 UINavigationController 添加 category

此方法來自 github:UIViewController-BackButtonHandler

由于系統的 UINavigationController 使用了一個 UINavigationBar 來管理 Controller 的 pop 和 push 等操作,所以仔細查看 UINavigationBar 的 API,會發現一個 UINavigationBarDelegate,它包含了四個方法:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPushItem:(UINavigationItem *)item; // called to push. return NO not to.
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item;    // called at end of animation of push or immediately if not animated
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;  // same as push methods
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;

我們會驚喜的第一個不就是我們想要的效果嗎?因為該方法返回 YES 則 pop,若返回NO,則不POP。

因此我們可以為 UINavigatonController 創建一個 Category,來定制navigationBar: shouldPopItem: 的邏輯。這里需要注意的是,我們不需要去設置 delegate,因為 UINavigatonController 自帶的 UINavigationBar 的 delegate 就是導航欄本身。這樣還有個問題就是,那在實際的 Controller 里面怎么控制呢?因此同樣需要對 UIViewController 添加一個 Protocol,這樣在 Controller 中使用該 Protocol 提供的方法即可進行控制了,代碼如下:

// UIViewController+BackButtonHandler.h
@protocol BackButtonHandlerProtocol <NSObject>
@optional
// 重寫下面的方法以攔截導航欄返回按鈕點擊事件,返回 YES 則 pop,NO 則不 pop
-(BOOL)navigationShouldPopOnBackButton;
@end

@interface UIViewController (BackButtonHandler) <BackButtonHandlerProtocol>

@end
// UIViewController+BackButtonHandler.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;
}

到這兒,幾乎就完美的解決一開始的問題了,使用方法也非常簡單

(1). 在一個 Controller 中:

#import "UIViewController+BackButtonHandler.h"

(2). 重寫 navigationShouldPopOnBackButton 方法

- (BOOL)navigationShouldPopOnBackButton{
    [[[UIAlertView alloc] initWithTitle:@"提示" message:@"確定返回上一界面?"
                               delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil] show];
    return NO;
}
// UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex{
    if (buttonIndex==1) {
        [self.navigationController popViewControllerAnimated:YES];
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,229評論 4 61
  • 天寒地凍時,角落里的陽光彌足珍貴。 最近的生活總是不盡如人意,仿佛整天有一大片烏云籠罩心頭。我狂奔著想擺脫掉但難過...
    邱紋閱讀 452評論 1 2
  • 年底都很忙。喜歡忙碌的感覺,充實。生活就是不斷的問題疊加,然后不斷的去解決。總想著一帆風順是不可能的。有時加班回家...
    一生為一人HT閱讀 206評論 1 0
  • 江城子 元旦 春城之夜披彩虹, 笑語聲,飄到空, 車滿街頭,節日氣氛濃。 努力方修幸福路, 肯拼搏,事終成。 雞來...
    春韻留芳閱讀 124評論 0 0
  • Web應用被應用開發者創建,這些開發者給予、賣應用,或者為了安裝到一個運行時環境,把應用轉移應用到一個部署者。應用...
    Lucky_Micky閱讀 2,597評論 0 1