UINavigationBar使用詳解

基本使用

// 設(shè)置導(dǎo)航欄的標(biāo)題
self.navigationItem.title = @"UINavigationBar使用總結(jié)";

// 設(shè)置導(dǎo)航欄的背景顏色
self.navigationController.navigationBar.barTintColor = [UIColor redColor];

// 設(shè)置導(dǎo)航欄的背景圖片
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"Background"] 
                                              forBarMetrics:UIBarMetricsDefault];

更改狀態(tài)欄的顏色

我們設(shè)置背景色或者背景圖之后,狀態(tài)欄依然還是默認(rèn)的黑色,這樣感覺不好看

  • UIStatusBarStyleDefault,系統(tǒng)的默認(rèn)樣式,黑色內(nèi)容,用于淺色的背景(如白色)
  • UIStatusBarStyleLightContent 白色內(nèi)容,用于深色的背景(如紅色)

在你的ViewController中添加下面的方法:

- (UIStatusBarStyle)preferredStatusBarStyle{
     return UIStatusBarStyleLightContent;
}

問題:

通常我們直接在viewWillAppearviewWillDisappear中修改導(dǎo)航欄的顏色或者圖片、隱藏導(dǎo)航欄等屬性時,容易出現(xiàn)問題:

  1. 前后兩個頁面如果顏色或者圖片不一樣,這樣設(shè)置動畫切換時很突兀 。
  2. 被push進(jìn)來的入口有很多,需要知道上層viewController的導(dǎo)航欄屬性,不然在viewWillDisappear中容易設(shè)錯屬性。

自定義導(dǎo)航欄(完美契合系統(tǒng))

因此我們往往需要自定義一個導(dǎo)航欄,來滿足我們的需求,比如?改造系統(tǒng)導(dǎo)航欄。

一、構(gòu)建基類BaseViewController

頭文件

@interface BaseViewController : UIViewController

@property (nonatomic, copy) UIColor *navBarColor;

@property (nonatomic, copy) UIImage *navBarImage;

@property (nonatomic, assign) CGFloat navBarAlpha;

@end

實現(xiàn)文件

@interface BaseViewController ()
@property (nonatomic, strong) UIImageView *backCustomView;
@end

@implementation BaseViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 將背景圖設(shè)置為空圖片,這樣導(dǎo)航欄就是透明的了
    [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
}

// 插入自定義的圖片,所有更改顏色、背景圖、透明度等屬性都是修改backCustomView屬性
- (UIImageView *)backCustomView {
    if (!_backCustomView) {
        _backCustomView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.navigationController.navigationBar.frame), 64)];
        [self.view addSubview:_backCustomView];
    }
    return _backCustomView;
}

- (void)setNavBarColor:(UIColor *)navBarColor {
    _navBarColor = [navBarColor copy];
    self.backCustomView.backgroundColor = navBarColor;
}

- (void)setNavBarImage:(UIImage *)navBarImage {
    self.backCustomView.image = navBarImage;
}

- (void)setNavBarAlpha:(CGFloat)navBarAlpha {
    self.backCustomView.alpha = navBarAlpha;
}
二、繼承基類,調(diào)用基類屬性
#import "BaseViewController.h"

@interface FirstViewController : BaseViewController
@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.navigationItem.title = @"First";
    self.navBarColor = [UIColor redColor];
}

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.navigationItem.title = @"Second";
    self.navBarImage = [UIImage imageForColor:[UIColor cyanColor]];
}

效果圖如下:


設(shè)置返回按鈕

我這里只講解怎么使用系統(tǒng)的返回按鈕,至于自定義的UIBarButtonItem* leftBarButton = [[UIBarButtonItem alloc] initWithCustomView:leftButtonView];不是我講解的重點。

如果當(dāng)前viewController是push進(jìn)來的,且沒設(shè)置self.navigationItem.leftBarButtonItem,那么導(dǎo)航欄默認(rèn)是有系統(tǒng)返回按鈕的,且title是上層viewController的title,可以統(tǒng)一修改返回標(biāo)題為“返回”。

@implementation BaseViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
   // 需要在基類中設(shè)置 
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:nil];
}

效果圖如下:


類似微信的返回+關(guān)閉按鈕

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.navigationItem.title = @"Second";
    
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(backClicked)];
    self.navigationItem.leftItemsSupplementBackButton = YES;
    

    // 解決左滑手勢失效問題  
    self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;
}

效果圖如下:


攔截返回事件

我們可以為 UINavigatonController 創(chuàng)建一個 Category,來定制navigationBar: shouldPopItem:的邏輯。這里需要注意的是,我們不需要去設(shè)置 delegate,因為 UINavigatonController 自帶的 UINavigationBar 的 delegate 就是導(dǎo)航欄本身。那在實際的 Controller 里面怎么控制呢?因此同樣需要對 UIViewController 添加一個 Protocol,這樣在 Controller 中使用該 Protocol 提供的方法即可進(jìn)行控制了。

一、UIViewController 添加 category
@protocol WDBackButtonHandlerProtocol <NSObject>
@optional
// 重寫下面的方法以攔截導(dǎo)航欄返回按鈕點擊事件,返回 YES 則 pop,NO 則不 pop
- (BOOL)wd_navigationShouldPopOnBackButton;
@end

@interface UIViewController (WDCustom) <WDBackButtonHandlerProtocol>

@end
二、UINavigationController 添加 category
#import "UINavigationController+WDCustom.h"

#import "UIViewController+WDCustom.h"

@implementation UINavigationController (WDCustom)

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
    
    BOOL shouldPop = NO;
    UIViewController *topVC = [self topViewController];
    BOOL canRespond = [topVC respondsToSelector:@selector(wd_navigationShouldPopOnBackButton)];
    
    if (!canRespond) {
        // 執(zhí)行系統(tǒng)的pop
        return YES;
    }
    
    // 判斷自定義pop
    shouldPop = [topVC wd_navigationShouldPopOnBackButton];
    
    if (shouldPop) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self popViewControllerAnimated:YES];
        });
    } else {
        // 取消 pop 后,復(fù)原返回按鈕的狀態(tài)
        for (UIView *subview in navigationBar.subviews) {
            if (subview.alpha > 0.0 && subview.alpha < 1.0) {
                [UIView animateWithDuration:0.25 animations:^{
                    subview.alpha = 1.0;
                }];
            }
        }
    }
    return NO;
}

使用方法很簡單

1、在基類中:

#import "UINavigationController+WDCustom.h"

2、子類重寫 protocol 中的 wd_navigationShouldPopOnBackButton 方法

@implementation SecondViewController

- (BOOL)wd_navigationShouldPopOnBackButton {
    // do something, e.g. webview goback
    return NO;
}

如果實現(xiàn)了該protocol,則可以做一些想做的事情,比如微信網(wǎng)頁回退,推到最后一個就pop,return YES就會觸發(fā)pop事件。

也可以不實現(xiàn)該protocol,那么點擊返回按鈕,默認(rèn)觸發(fā)pop。

代碼在這里

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,229評論 4 61
  • 前言 由于最近兩個多月,筆者正和小伙伴們忙于對公司新項目的開發(fā),筆者主要負(fù)責(zé)項目整體架構(gòu)的搭建以及功能模塊的分工。...
    CoderMikeHe閱讀 27,122評論 74 270
  • 七月份決定要補習(xí)的時候,感覺補習(xí)會是一件比較輕松的事,高三的努力不是白費的,回頭想想這三個月,其實一點也不輕松。 ...
    月jason閱讀 244評論 1 5
  • 不喜歡的人依舊那么討厭,昨天我舅媽打電話來說要我媽把工作辭了 ,然后外婆由三兄妹一個月輪流照顧,要么每個月出錢,其...
    沅韻閱讀 178評論 0 2
  • 村長是一個血統(tǒng)純正的伯恩山,當(dāng)時我表哥帶著一個只有我膝蓋下面一點高度的它跟我介紹著它的父母都是什么什么金牌,而我并...
    kanoko閱讀 567評論 0 1