先說一下做這個的思路,其實很簡單的,一共就3步:
(1) 隱藏系統默認的導航欄;
(2)自定義一個NavigationBar;
(3)在原來導航欄的位置放置自定義的NavigationBar。
下面我們一步一步實現。
(1)隱藏系統默認的導航欄:
自定義一個NavigationController,在這個類里只做一件事情,那就是隱藏系統默認的導航欄,代碼如下:
- (void)awakeFromNib { [super awakeFromNib]; // 隱藏默認導航欄 self.navigationBarHidden = NO; // 使右滑返回手勢可用 self.navigationBar.hidden = YES; // 隱藏導航欄 }
另外需要注意的是:
不能直接用 self.navigationBarHidden = YES來隱藏導航欄,因為用這個屬性的話,系統默認的右滑返回手勢就沒有了,切記,一定要用self.navigationBar.hidden = YES來隱藏,並將self.navigationBarHidden的值設為YES(默認就是YES,所以可以不用加這句)。
不能直接用 self.navigationBarHidden = YES來隱藏導航欄,因為用這個屬性的話,系統默認的右滑返回手勢就沒有了,切記,一定要用self.navigationBar.hidden = YES來隱藏,並將self.navigationBarHidden的值設為YES(默認就是YES,所以可以不用加這句)。
(2)自定義一個NavigationBar:
根據自己的需求,自定義一個NavigationBar,我在這里自定義了一個UIView的子類,叫YSNavigationBar,用Xib實現的,我把這個View分成了3部分,左邊的按鈕,中間的標題,右側的按鈕,模擬一下系統默認的導航欄,實現起來也很簡單,代碼如下:
YSNavigationBar.h:
#import <UIKit/UIKit.h> typedef void(^NavBtnClickBlock)(); @interface YSNavigationBar : UIView @property (weak, nonatomic) IBOutlet UIView *leftView; @property (weak, nonatomic) IBOutlet UIView *rightView; @property (weak, nonatomic) IBOutlet UIView *centerView; @property (weak, nonatomic) IBOutlet UIButton *leftBtn; @property (weak, nonatomic) IBOutlet UIButton *rightBtn; @property (weak, nonatomic) IBOutlet UILabel *centerLbl; @property (nonatomic, copy) NavBtnClickBlock leftBtnClickHandler; @property (nonatomic, copy) NavBtnClickBlock rightBtnClickHandler; @end
YSNavigationBar.m:
#import "YSNavigationBar.h" @implementation YSNavigationBar - (void)awakeFromNib { [super awakeFromNib]; // 初始化界面 [self initAllView]; } - (void)initAllView { self.backgroundColor = [UIColor greenColor]; self.leftView.backgroundColor = [UIColor clearColor]; self.centerView.backgroundColor = [UIColor clearColor]; self.rightView.backgroundColor = [UIColor clearColor]; // 默認右側按鈕隱藏 self.rightView.hidden = YES; } #pragma mark - event response - (IBAction)leftBtnClick:(UIButton *)sender { if (_leftBtnClickHandler) { _leftBtnClickHandler(); } } - (IBAction)rightBtnClick:(UIButton *)sender { if (_rightBtnClickHandler) { _rightBtnClickHandler(); } } @end
YSNavigationBar.xib:
(3)在原來導航欄的位置放置自定義的NavigationBar:
現在默認的導航欄已經隱藏了,自定義的導航欄也有了,下面就要進行最后一步了,那就是在原來導航欄的位置放置自定義的NavigationBar。
因為可能會有很多頁面需要自定義導航欄,所以我們需要一個父類,所有需要自定義導航欄的VC都繼承它。自定義一個UIViewController的子類YSBaseViewController,將這個類作為所有需要自定義導航欄的VC的父類,代碼如下:
YSBaseViewController.h:
#import <UIKit/UIKit.h> @class YSNavigationBar; @interface YSBaseViewController : UIViewController @property (nonatomic, copy) NSString *titleStr; // 導航欄標題 @property (nonatomic, assign) BOOL leftButtonHidden; @property (nonatomic, assign) BOOL rightButtonHidden; @property (nonatomic, strong) UIColor *navBgColor; // 導航欄背景色 @property (readonly, nonatomic, strong) UIButton *leftButton; @property (readonly, nonatomic, strong) UIButton *rightButton; @property (readonly, nonatomic, strong) UILabel *centerLabel; - (void)replaceDefaultNavBar:(UIView *)nav; @end
YSBaseViewController.m:
#import "YSBaseViewController.h" #import "YSNavigationBar.h" #import "UIView+UIViewCreateFromXib.h" @interface YSBaseViewController () @property (nonatomic, strong) YSNavigationBar *navigationBar; // 自定義的導航欄 @end @implementation YSBaseViewController - (void)viewDidLoad { [super viewDidLoad]; // 初始化導航欄 [self initNavigationBar]; } #pragma mark - getter/setter - (void)setTitleStr:(NSString *)titleStr { _titleStr = titleStr; self.centerLabel.text = titleStr; } - (void)setLeftButtonHidden:(BOOL)leftButtonHidden { _leftButtonHidden = leftButtonHidden; self.leftButton.hidden = leftButtonHidden; } - (void)setRightButtonHidden:(BOOL)rightButtonHidden { _rightButtonHidden = rightButtonHidden; _navigationBar.rightView.hidden = rightButtonHidden; } - (void)setNavBgColor:(UIColor *)navBgColor { _navBgColor = navBgColor; _navigationBar.backgroundColor = navBgColor; } - (UIButton *)leftButton { NSAssert(_navigationBar, @"_navigationBar == nil"); if (_navigationBar) { return _navigationBar.leftBtn; } return nil; } - (UIButton *)rightButton { NSAssert(_navigationBar, @"_navigationBar == nil"); if (_navigationBar) { return _navigationBar.rightBtn; } return nil; } - (UILabel *)centerLabel { NSAssert(_navigationBar, @"_navigationBar == nil"); if (_navigationBar) { return _navigationBar.centerLbl; } return nil; } #pragma mark - public methods - (void)replaceDefaultNavBar:(UIView *)nav { NSAssert(nav, @"nav == nil"); if (nav) { [_navigationBar removeFromSuperview]; _navigationBar = nil; [self.view addSubview:nav]; [self addConstraintsWithView:nav]; } } #pragma mark - private methods - (void)initNavigationBar { if (!_navigationBar) { _navigationBar = [YSNavigationBar createViewFromXib]; // 這句話必須加上,否則約束就有問題 _navigationBar.translatesAutoresizingMaskIntoConstraints = NO; } [self.view addSubview:_navigationBar]; [self addConstraintsWithView:_navigationBar]; if (self.navigationController) { if (self.navigationController.viewControllers[0] == self) { self.leftButton.hidden = YES; } else { self.leftButton.hidden = NO; } } // 默認左側返回按鈕 [self.leftButton setImage:[UIImage imageNamed:@"YSBackBtn"] forState:UIControlStateNormal]; [self.leftButton setTitle:@"" forState:UIControlStateNormal]; __weak typeof(self) weakSelf = self; // 給左側按鈕添加默認事件 _navigationBar.leftBtnClickHandler = ^() { __strong typeof(self) strongSelf = weakSelf; [strongSelf defaultLeftBtnClick]; }; // 給右側按鈕添加默認事件 _navigationBar.rightBtnClickHandler = ^() { __strong typeof(self) strongSelf = weakSelf; [strongSelf defaultRightBtnClick]; }; } #pragma mark 給自定義導航欄添加約束 - (void)addConstraintsWithView:(UIView *)view { // top NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; // left NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]; // right NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]; [self.view addConstraints:@[topConstraint, leftConstraint, rightConstraint]]; // height NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:view.bounds.size.height]; [view addConstraint:heightConstraint]; } #pragma mark 子類可以重寫來實現不同的功能 - (void)defaultLeftBtnClick { NSAssert(self.navigationController, @"self.navigationController == nil"); if (self.navigationController) { [self.navigationController popViewControllerAnimated:YES]; } } - (void)defaultRightBtnClick { } @end
到這里,我們的工作基本已經完成,下面需要做的就是繼承YSBaseViewController這個類,就OK了!
因為UIView默認是不能直接創建Xib文件的,所以我在這里寫了一個UIView的Category,用來加載Xib,代碼如下:
#import "UIView+UIViewCreateFromXib.h" @implementation UIView (UIViewCreateFromXib) + (instancetype)createViewFromXib { NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:self options:nil]; NSAssert(nibs && nibs.count != 0, @"獲取Nib失敗!"); return nibs[0]; } @end