基本使用
// 設(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;
}
問題:
通常我們直接在
viewWillAppear
和viewWillDisappear
中修改導(dǎo)航欄的顏色或者圖片、隱藏導(dǎo)航欄等屬性時,容易出現(xiàn)問題:
- 前后兩個頁面如果顏色或者圖片不一樣,這樣設(shè)置動畫切換時很突兀 。
- 被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。
代碼在這里