iOS開發之自定義導航欄


先說一下做這個的思路,其實很簡單的,一共就3步:

(1) 隱藏系統默認的導航欄;

(2)自定義一個NavigationBar;

(3)在原來導航欄的位置放置自定義的NavigationBar。

下面我們一步一步實現。

(1)隱藏系統默認的導航欄:

自定義一個NavigationController,在這個類里只做一件事情,那就是隱藏系統默認的導航欄,代碼如下:
- (void)awakeFromNib {
    [super awakeFromNib];
    // 隱藏默認導航欄
    self.navigationBarHidden = NO; // 使右滑返回手勢可用
    self.navigationBar.hidden = YES; // 隱藏導航欄
}
   因為我是在storyboard中實現的,所以在awakeFromNib方法中隱藏默認的導航欄。
另外需要注意的是:
   不能直接用 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM