天天看點

自定義導航欄傳回按鈕點選事件

開發中經常會遇到 點選導航欄傳回按鈕時不想 pop 回上一級控制器,而是回到 某一級控制器 或者需要在pop回去的時候回傳一些資料,但檢視文檔發現,系統并沒有給我們直接提供這樣的方法。

那麼我們先來分析如何擷取傳回按鈕的點選事件。

傳回按鈕在導航欄上,是以我們先找到導航控制器UINavigationController的頭檔案,他有一個屬性

@property(nonatomic,readonly) UINavigationBar *navigationBar;

我們知道傳回按鈕就在 navigationBar上,在看一下 UINavigationBar 的頭檔案,我們并沒有發現有傳回按鈕的屬性或者傳回按鈕的點選方法;

但是我們發現 navigationBar 有一個代理屬性

@property(nullable,nonatomic,weak) id delegate;

檢視 UINavigationBarDelegate 的方法中有一個方法是:

- (BOOL)navigationBar:(UINavigationBar )navigationBar shouldPopItem:(UINavigationItem )item; // same as push methods

哈哈,從方法名上我們已經看出這個方法就是我們要找的了!

由于navigationBar 是NavigationController的屬性,我們推測 navigationBar 的 代理就是NavigationController, 于是我就在 NavigationController 裡重寫了上面那個代理方法,發現在點選傳回按鈕的時候,确實調用了這個方法,^^ 有沒有覺得我們已經接近真相了 O(∩∩)O

等不及啦,直接上代碼了

寫一個導航控制器的基類

#import <UIKit/UIKit.h>

@interface GZNavigationController : UINavigationController

@end

---------------------------

#import "GZNavigationController.h"
#import "GZViewController.h"

@interface GZNavigationController ()

@end

@implementation GZNavigationController

- (void)viewDidLoad {
    [super viewDidLoad];

}

#pragma mark - UINavigationBarDelegate
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
{
    if (self.viewControllers.count > ) {
        GZViewController *topVc = (GZViewController *)self.viewControllers.lastObject;
        BOOL isPop = YES;
        if ([topVc respondsToSelector:@selector(shouldPopItem)]) {
            isPop = [topVc performSelector:@selector(shouldPopItem)];
            if (isPop) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self popViewControllerAnimated:YES];
                });
            } else {
            //shouldPopItem 方法傳回no時發現傳回按鈕的圖示,顔色變淡了,周遊導航欄上的子空間,修改它的透明度為1
                for(UIView *subview in [navigationBar subviews]) {
                    if(subview.alpha < ) {
                        [UIView animateWithDuration: animations:^{
                            subview.alpha = ;
                        }];
                    }
                }
            }
            return NO;
        }
    }
    return YES;
}

@end

           

寫一個視圖控制器的基類

@interface GZViewController : UIViewController


/**
 自定義導航欄傳回按鈕的點選事件方法

 @return 是否傳回上一級控制器 ,return YES 傳回上一級控制器,如果不想傳回上一級控制器,可以重寫此方法,處理完自己的邏輯後  return  NO;
 */
- (BOOL) shouldPopItem;

@end

--------------------------

#import "GZViewController.h"

@interface GZViewController ()

@end

@implementation GZViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}
- (BOOL) shouldPopItem
{
    //基類中預設 傳回YES,也就是pop到上一級控制器
    return YES;
}

@end
           

子類隻需要重寫 - (BOOL) shouldPopItem 方法,就可以自定義傳回按鈕的點選事件了。

如有問題,歡迎評論交流!