前言
隨著項目功能的需要魔眨,可能有些界面的導航條比較特殊媳维,比如
- 需要添加不同的按鈕,比如掃碼遏暴,心愿單侄刽,分享,更多等等朋凉。
- 需要將菜單替換成圖片
- 需要隱藏整個導航條
- 需要隨著滾動州丹,導航條背景跟著變色
- 隱藏導航條底部的線條
- ...
所以自定義一個導航條就顯得至關重要了。
效果圖
addGes.gif
實現(xiàn)思路
- 1.自定義一個導航條視圖
NaviBarView
,并且對外提供各種方法可以動態(tài)修改要展示的內(nèi)容墓毒。 - 2.定義一個 VC 的基類吓揪,項目中所有的 VC 都繼承它。在它里面創(chuàng)建并且維護一個導航條所计,隱藏系統(tǒng)自帶的導航條磺芭,并且對外提供各種方法。
部分相關代碼如下
1.NaviBarView類的實現(xiàn)
- NaviBarView.h
#import <UIKit/UIKit.h>
@class BaseViewController;
#define StatusBarHeight [[UIApplication sharedApplication] statusBarFrame].size.height
#define NavBarHeight 44
#define NavHeight (StatusBarHeight + NavBarHeight)
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
/**
導航條
*/
@interface NaviBarView : UIView
@property (retain, nonatomic) UIView *statusBar; // 狀態(tài)欄
@property (retain, nonatomic) UIView *navigationBar; // 導航條
@property (retain, nonatomic) UIButton *rightWishBtn; // 右側分享按鈕
@property (retain, nonatomic) UIButton *leftMenuBtn; // 左側菜單欄
@property (retain, nonatomic) UIButton *backBtn; // 返回按鈕
@property (retain, nonatomic) UILabel *titleLabel; // 標題
@property(nonatomic, strong)UIView *lineView; // 底部分割線
- (instancetype)initWithController:(BaseViewController *)controller;
// 掃碼和心愿單
- (void)addScanAndWishList;
// 添加返回按鈕
- (void)addBackBtn;
// 添加底部分割線
- (void)addBottomSepLine;
// 設置標題
- (void)setNavigationTitle:(NSString *)title;
// 設置導航條透明
- (void)clearNavBarBackgroundColor;
// 右側添加按鈕
- (UILabel *)addRightMenu:(NSString *)actionName withAction:(SEL)action;
@end
-
NaviBarView.m
初始化
// 初始化
- (instancetype)initWithController:(BaseViewController *)controller {
_controller = controller;
self = [super initWithFrame:CGRectMake(0, 0, ScreenWidth, NavHeight)];
self.backgroundColor = [UIColor clearColor];
self.layer.zPosition = 999999;
// 最頂部的狀態(tài)欄
_statusBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, StatusBarHeight)];
_statusBar.backgroundColor = [UIColor whiteColor];
[self addSubview:_statusBar];
_navigationBar = [[UIView alloc] initWithFrame:CGRectMake(0, StatusBarHeight, ScreenWidth, NavBarHeight)];
_navigationBar.backgroundColor = [UIColor whiteColor];
[self addSubview:_navigationBar];
return self;
}
-
NavBarView.m
添加視圖 - 只羅列部分代碼
// 返回按鈕
- (void)addBackBtn {
// 不能添加多個
UIView *srcBack = [_navigationBar viewWithTag:TagBackBtn];
if (srcBack)
return;
UIImage *background = [[UIImage imageNamed:@"nav_back_black"] ifRTLThenOrientationUpMirrored];
UIImage *backgroundOn = [[UIImage imageNamed:@"nav_back_black"] ifRTLThenOrientationUpMirrored];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setAccessibilityIdentifier:@"TopBackBtn"];
button.tag = TagBackBtn;
[button onTap:self action:@selector(doBackPrev)];
[button setImage:background forState:UIControlStateNormal];
[button setImage:backgroundOn forState:UIControlStateHighlighted];
button.frame = CGRectMake(0, 0, 60, 44);
button.contentEdgeInsets = UIEdgeInsetsMake(7, 7, 7, 20);
[_navigationBar addSubview:button];
[button rtlToParent];
_backBtn = button;
}
// 添加頂部右邊的文字類的按鈕
- (UILabel *)addRightMenu:(NSString *)actionName withAction:(SEL)action {
// 當重復添加時,移除舊的按鈕
UILabel *srcLabel = (UILabel *)[_navigationBar viewWithTag:TagRightMenu];
if (srcLabel) {
[srcLabel removeFromSuperview];
}
UILabel *lb = [[UILabel alloc] initWithFrame:CGRectMake(ScreenWidth - 110, 0, 100, 44)];
lb.backgroundColor = [UIColor clearColor];
lb.font = [UIFont systemFontOfSize:16];
lb.textColor = [UIColor blackColor];
lb.text = actionName;
lb.userInteractionEnabled = YES;
lb.textAlignment = NSTextAlignmentRight;
lb.tag = TagRightMenu;
[lb onTap:_controller action:action];
[_navigationBar addSubview:lb];
[lb rtlToParent];
_rightMenuView = lb;
return lb;
}
-
NaviBarView.m
- 一些設置方法
#pragma mark - set
- (void)clearNavBarBackgroundColor {
_statusBar.backgroundColor = [UIColor clearColor];
_navigationBar.backgroundColor = [UIColor clearColor];
_titleLabel.textColor = [UIColor whiteColor];
[_navigationBar removeChildByTag:kTagLine];
}
- (void)setNavigationTitle:(NSString *)title {
self.titleLabel.text = title;
}
- (void)setBackImage:(NSString *)imageName {
UIImage *background = [UIImage imageNamed:imageName];
UIImage *backgroundOn = [UIImage imageNamed:imageName];
[_backBtn setImage:background forState:UIControlStateNormal];
[_backBtn setImage:backgroundOn forState:UIControlStateHighlighted];
}
####### 2.BaseViewController
基類的實現(xiàn)
-
BaseViewController.h
部分代碼
/**
基類
*/
@interface BaseViewController : UIViewController
#pragma mark - 導航條相關
@property(nonatomic, copy)NSString *naviTitle; // 標題
/** 導航條 */
@property(nonatomic, strong)NaviBarView *topNavBar;
/** 內(nèi)容視圖 */
@property (strong, nonatomic) UIView *containerView;
// 返回按鈕點擊操作
- (void)doBackPrev;
// 掃碼和心愿單
- (void)addScanAndWishList;
// 設置導航條透明
- (void)clearNavBarBackgroundColor;
// 添加按鈕
- (UIButton *)addBtnWithTitle:(NSString *)title action:(SEL)action;
- (UILabel *)addRightMenu:(NSString *)actionName withAction:(SEL)action;
@end
-
BaseViewController.m
實現(xiàn)
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
// setup data
self.view.backgroundColor = [UIColor whiteColor];
// 所有界面隱藏導航欄,用自定義的導航欄代替
self.fd_prefersNavigationBarHidden = YES;
// drawUI
[self drawTopNaviBar];
}
@end
為什么要設置
fd_prefersNavigationBarHidden
參數(shù)為 YES醉箕,因為本項目是使用FDFullscreenPopGesture
來管理導航條钾腺,隱藏系統(tǒng)的導航條已經(jīng)被它所實現(xiàn)了。
- (void)fd_viewWillAppear:(BOOL)animated
{
// Forward to primary implementation.
[self fd_viewWillAppear:animated];
if (self.fd_willAppearInjectBlock) {
self.fd_willAppearInjectBlock(self, animated);
}
//設置導航的顯示/隱藏
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(CGFLOAT_MIN * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIViewController *vc = [self.navigationController.viewControllers lastObject];
if (vc.fd_prefersNavigationBarHidden) {
[self.navigationController setNavigationBarHidden:YES animated:NO];
} else {
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
});
}
- 在界面即將顯示的時候讥裤,將導航條推至最前面放棒,避免被其他視圖遮擋
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.navigationController.navigationBar.height == 0) {
_topNavBar.alpha = 0;
}
// 將導航放到最頂部,不然后面有其它的層會被覆蓋
[self.view bringSubviewToFront:_topNavBar];
}
- 導航條的繪制
/// 在旋轉界面時重新構造導航條
- (void)drawTopNaviBar {
if (_topNavBar) {
[_topNavBar removeFromSuperview];
}
// 添加自定義的導航條
NaviBarView *naviBar = [[NaviBarView alloc] initWithController:self];
[self.view addSubview:naviBar];
self.topNavBar = naviBar;
if (![self isKindOfClass:[HomeViewController class]] && ![self isKindOfClass:[AccountViewController class]]) {
// 添加返回按鈕
[_topNavBar addBackBtn];
// 添加底部分割線 - 如果不需要添加,這里處理即可
[_topNavBar addBottomSepLine];
}
// 自動放一個容器在下面,如果全屏的界面就往 self.view 加子,非全屏的往 container 加
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, NavHeight, ScreenWidth, ScreenHeight - NavHeight)];
self.containerView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.containerView];
}
- 還有其他代碼請下載本文的項目即可
3.使用
- 新建的 VC 必須繼承自
BaseViewController
才可以使用
3.1 導航條添加掃碼,搜索己英,心愿單功能
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// 添加掃碼,搜索,心愿單
[self addScanAndWishList];
}
image.png
3.2 導航條正常樣式+右側添加分享圖標
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.naviTitle = @"First VC";
[self addRightMenu:@"分享" withAction:@selector(tapShare)];
}
image.png
3.3 導航條只有返回按鈕间螟,沒有標題,沒有底部線條
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.naviTitle = @"隱藏導航條分割線";
[self clearNavBarBackgroundColor];
}
image.png
更多功能损肛,只需要根據(jù)需要厢破,自定義導航條視圖類NaviBarView
即可。
- 如有錯誤治拿,歡迎指正摩泪,多多點贊,打賞更佳劫谅,您的支持是我寫作的動力见坑。