不以圖片開頭的文章都不是好文章
任何時候,都不要迷失自己。有一雙清澈的眼睛,可以沉默,但不要迷離方向;有一顆干凈的心靈,可以容納,但不能承載太多;有一個優雅的姿態,可以美麗,但不要沉溺世事。其實,一切源于自然,源于清凈,源于靈魂的修行。
現狀描述:
一般項目中大概都是一個tabbar管理幾個帶導航的控制器,可其中有幾個控制器沒有導航。這時候就需要進入該控制器的時候隱藏導航,離開的時候顯示導航。
大概流程就是設置代理 self.navigationController.delegate = self;
遵守協議 UINavigationControllerDelegate
#pragma mark - UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
并在viewWillAppear
中隱藏
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
在viewWillDisappear
中顯示導航,設置回導航,例如:
UIImage *image= [self createImageWithColor:kMainColor];
[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
//其中:createImageWithColor:是根據傳遞主題顏色生成圖片
/*
- (UIImage *)createImageWithColor:(UIColor*)color {
CGRect rect = CGRectMake(0, 0, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}*/
發現Bug:
以上這種寫法,一般也不會有啥問題。除非遇到跳轉的界面也是隱藏導航的,這時候有概率出現該顯示導航的卻消失了(復現過程:滑動來回調用viewWillAppear
和viewWillDisappear
)
構思解決方案:
所以干脆讓導航一直都是隱藏狀態,顯示的時候添加自定義的導航View,當然功能都參照著系統的功能
實施大致過程關鍵Code:
- 初始化 懶加載控件
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initView];
}
return self;
}
- (void)initView {
self.backgroundColor = [UIColor redColor];///kMainColor;
//根據公開傳遞的參數按需增加
//默認加載灰色的線
[self bottomGrayLine];
[self backBtn];
}
- 返回按鈕
/// 返回按鈕 默認添加 參照leftBarButtonItem
- (JYDisableHightlightBtn *)backBtn {
if (!_backBtn) {
_backBtn = [JYDisableHightlightBtn buttonWithType:(UIButtonTypeCustom)];
[self addSubview:_backBtn];
//Masonry約束
[_backBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(15);
make.width.equalTo(80);
make.height.equalTo(44);
make.bottom.equalTo(0);
}];
_backBtn.backgroundColor = [UIColor blueColor];
[_backBtn setImage:[UIImage imageNamed:@"common_back"] forState:(UIControlStateNormal)];
//按鈕圖片居左
_backBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
//點擊響應RAC傳遞信號
[[_backBtn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
if (self.leftBtnClickedBlock) { //使用block自定義返回或返回根視圖
self.leftBtnClickedBlock();
}else {
[self.viewController.navigationController popViewControllerAnimated:YES];
}
}];
}
return _backBtn;
}
- 中間的標題
//中間的標題
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc]init];
[self addSubview:_titleLabel];
[_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.mas_centerX);
make.bottom.equalTo(-10);
}];
_titleLabel.backgroundColor = [UIColor blueColor];
_titleLabel.font = [UIFont systemFontOfSize:18];
_titleLabel.textColor = [UIColor whiteColor];
}
return _titleLabel;
}
- 在頭文件中公開屬性,方便設置導航按鈕等,如:
//背景
@property (nonatomic, copy) NSString *jy_naviImageName; //titleView
@property (nonatomic, assign) BOOL jy_hideBottomGrayLine;
//左邊
@property (nonatomic, copy) void (^leftBtnClickedBlock)(void); //left
@property (nonatomic, assign) BOOL jy_hiddenBackBtn;
@property (nonatomic, copy) void (^leftBtnsClickedBlock)(UIButton *leftBtns); //lefts需要
//中間
@property (nonatomic, copy) NSString *titleString;
@property (nonatomic, copy) NSString *titleImageString;
- 當然還要仿照系統
UINavigationItem
還有titleView
、rightBarButtonItem
、rightBarButtonItems
以及是否隱藏返回按鈕,右側是否可點擊等等
- 最后在基類中隱藏導航并添加自定義導航視圖,后續創建的控制器需要繼承自該基類
/*
設置父類的導航代理,隱藏導航,并添加自定義導航
*/
#import "JYBaseViewController.h"
@interface JYBaseViewController ()<UINavigationControllerDelegate>
@end
@implementation JYBaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.delegate = self;
self.baseNaviView = [[JYNaviView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth, k_Height_NavBar)];
[self.view addSubview:self.baseNaviView];
}
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
#pragma mark - dealloc
- (void)dealloc{
NSLog(@"%@--dealloc", [self className]);
}
整合到項目中實際遇到的問題:
-
UISearchController
的searchBar
點擊的時候會跑到頂部
解決辦法:個人建議直接使用UISearchBar
設置樣式后調用原來的邏輯。 - 同一個界面直接顯示和配合WMPageController使用。
解決辦法:在其中任意一個推出界面時增加type屬性(或成員變量),根據屬性來判斷是否隱藏導航視圖。如:
初始化賦值type,枚舉最好,此處簡寫
- (instancetype)initWithWMPage:(NSInteger)type {
if (self = [super init]) {
_type = type;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
if (self.type == 1) {
self.baseNaviView.hidden = YES;
}else {
self.baseNaviView.titleString = @"微視頻";
self.baseNaviView.hidden = NO;
}
//...
CGFloat startY = self.baseNaviView.hidden ? 0 : CGRectGetMaxY(self.baseNaviView.frame);
CGFloat videoH = self.baseNaviView.hidden ? ScreenHeight - self.tabBarController.tabBar.height- k_Height_NavBar - 41 : ScreenHeight- k_Height_NavBar- k_Height_Bottom;
self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, startY, ScreenWidth, videoH) style:(UITableViewStylePlain)]; //只有導航沒有tabbar,劉海屏系列減34,非減0
}
有的界面不顯示自定義的導航視圖
解決辦法:查看視圖層級,如果被遮擋那就帶到最前方[self.view bringSubviewToFront:self.baseNaviView];
子視圖被遮擋
解決辦法:如果是代碼創建的視圖,那么創建的時候CGRectMake的Y參數使用CGRectGetMaxY(self.baseNaviView.frame)
或者k_Height_navBar
,高度看情況是否需要再減掉。如果是Xib拖的控件,那么建議top約束到superView而不是Safe Area,然后在控制器中self.safeToTop.constant = k_Height_NavBar;
執行Block會警告:Capturing 'self' strongly in this block is likely to lead to a retain cycle
解決辦法:建議導入RAC框架或YYCategories,創建弱引用self
@weakify(self)
self.baseNaviView.leftBtnClickedBlock = ^{
@strongify(self)
[self.navigationController popToRootViewControllerAnimated:YES];
};
...
- BTW:Demo
煩惱都忘掉.JPG