最近用淘宝、网易云音乐这些App时发现他们的导航栏跟系统默认的不太一样,系统默认的是导航栏不动,导航栏上的内容渐变,而淘宝、网易云音乐都是导航栏跟着界面一起运动,于是就想研究一下,上网找了一下资料,找到了一个感觉还算不错的Demo,我也做了一下总结,主要是为了学习,有写的不好的地方希望大家能够指正,下面开始。
先说一下做这个的思路,其实很简单的,一共就3步:
(1)隐藏系统默认的导航栏;
(2)自定义一个NavigationBar;
(3)在原来导航栏的位置放置自定义的NavigationBar。
下面我们一步一步实现。
- (void)awakeFromNib {
[super awakeFromNib];
// 隐藏默认导航栏
self.navigationBarHidden = NO; // 使右滑返回手势可用
self.navigationBar.hidden = YES; // 隐藏导航栏
}
因为我是在storyboard中实现的,所以在awakeFromNib方法中隐藏默认的导航栏。
根据自己的需求,自定义一个NavigationBar,我在这里自定义了一个UIView的子类,叫YSNavigationBar,用Xib实现的,我把这个View分成了3部分,左边的按钮,中间的标题,右侧的按钮,模拟一下系统默认的导航栏,实现起来也很简单,代码如下:
YSNavigationBar.h:
//
// YSNavigationBar.h
// 自定义NavigationBar_01
//
// Created by 张延深 on 16/2/2.
// Copyright © 2016年 宜信. All rights reserved.
// 自定义的导航栏
#import
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:
//
// YSNavigationBar.m
// 自定义NavigationBar_01
//
// Created by 张延深 on 16/2/2.
// Copyright © 2016年 宜信. All rights reserved.
//
#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:
因为可能会有很多页面需要自定义导航栏,所以我们需要一个父类,所有需要自定义导航栏的VC都继承它。自定义一个UIViewController的子类YSBaseViewController,将这个类作为所有需要自定义导航栏的VC的父类,代码如下:
YSBaseViewController.h:
//
// YSBaseViewController.h
// 自定义NavigationBar_01
//
// Created by 张延深 on 16/2/2.
// Copyright © 2016年 宜信. All rights reserved.
// ViewController的基类,想要自定义导航栏的继承它。
#import
@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:
//
// YSBaseViewController.m
// 自定义NavigationBar_01
//
// Created by 张延深 on 16/2/2.
// Copyright © 2016年 宜信. All rights reserved.
//
#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,代码如下:
//
// UIView+UIViewCreateFromXib.m
// 自定义NavigationBar_01
//
// Created by 张延深 on 16/2/2.
// Copyright © 2016年 宜信. All rights reserved.
//
#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
over,在这里要感谢jimple,下面是他的关于自定义导航栏的文章: iOS自定义的导航条:CustomNavigationBar
谢谢!