前些天產(chǎn)品汪找到我,滑動(dòng)著nice的首頁(yè),跟我說(shuō):“小新!能否實(shí)現(xiàn)像nice這樣的,上滑讓導(dǎo)航欄消失,下滑讓導(dǎo)航欄顯示”?!巴耆梢?,一行代碼的事兒”我自信的回答。因?yàn)榫W(wǎng)上一搜:怎么像safari一樣滑動(dòng)的時(shí)候隱藏navigation bar?都會(huì)告訴你一行代碼就搞定。這一行代碼就是:
navigationController.hidesBarsOnSwipe = Yes
當(dāng)然這句代碼確實(shí)可以實(shí)現(xiàn)這個(gè)效果,我馬上讓產(chǎn)品汪看,想顯示自己的能力,結(jié)果產(chǎn)品汪說(shuō):“是不是狀態(tài)欄沒(méi)有背景?狀態(tài)欄不應(yīng)該是透明的”。仔細(xì)對(duì)比發(fā)現(xiàn):nice的狀態(tài)欄不僅有個(gè)背景,而且它們navigationBar消失的時(shí)候是從狀態(tài)欄顯示的時(shí)間下面經(jīng)過(guò)的。
直接使用navigationController.hidesBarsOnSwipe = Yes的效果圖如下:

nice的效果圖如下:


到這里是不是發(fā)現(xiàn)“這一行代碼的事兒”有點(diǎn)大了。很顯然這一行代碼搞不定了,于是乎開(kāi)始想辦法給狀態(tài)欄添加背景,網(wǎng)上有一堆資料,但對(duì)這個(gè)效果一點(diǎn)用都沒(méi)有,如果導(dǎo)航欄是一直顯示著,可能還可以湊合著用,但現(xiàn)在是...
無(wú)奈之下就自己“操刀了”給狀態(tài)欄添加背景:在- (void)viewWillAppear:(BOOL)animated;方法中實(shí)現(xiàn):
UIView *statusView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenW, 20)];
statusView.backgroundColor = [UIColor whiteColor];
self.statusView = statusView;
[[UIApplication sharedApplication].keyWindow addSubview:self.statusView];
就這樣就給狀態(tài)欄添加上了背景,但是這個(gè)背景會(huì)在其它控制器中依然存在,因?yàn)槲覀兗拥搅薻eywindow上,因?yàn)閚av是透明的就會(huì)出現(xiàn)下面的不協(xié)調(diào)顯示,讓人感覺(jué)不爽。

有人可能會(huì)說(shuō)在首頁(yè)消失的我們?cè)? (void)viewWillDisappear:(BOOL)animated;方法中將它移出就行了。對(duì)這樣可以,只需:[self.statusView removeFromSuperview];即可,倘若我們不是所有控制器都需要滑動(dòng)的時(shí)候隱藏navigation bar還需加上self.navigationController.hidesBarsOnSwipe = NO;并且在- (void)viewWillAppear:(BOOL)animated;中加上self.navigationController.hidesBarsOnSwipe = YES;。
這樣做其它控制確實(shí)不在有這樣的情況了,但是首頁(yè)這個(gè)不協(xié)調(diào)的顯示依然在,怎么辦。那就直接禁止它透明,都設(shè)成白色的背景行了,對(duì)這樣是可以的,只需self.navigationController.navigationBar.translucent = YES;即可。
至此我們是給狀態(tài)欄添加上背景了,也實(shí)現(xiàn)了像safari一樣滑動(dòng)的時(shí)候隱藏navigation bar。但是我們沒(méi)有實(shí)現(xiàn)navigationBar消失的時(shí)候是從狀態(tài)欄顯示的時(shí)間下面經(jīng)過(guò)的。這只是一個(gè)細(xì)節(jié),實(shí)在實(shí)現(xiàn)不了就跟經(jīng)理說(shuō),也許做成這個(gè)樣子就行了。但是我們要嚴(yán)格要求自己,這正是我們提高能力的時(shí)候。
于是乎我冒出一個(gè)想法:自己寫(xiě)。也就有了這篇文章的高潮部分了。
首先,需要搞清楚5點(diǎn)。
1、- (void)bringSubviewToFront:(UIView *)view;的使用;
2、UIScrollView 的contentOffset屬性的含義(寫(xiě)dome的過(guò)程中我試圖通過(guò)改contentOffset的y值來(lái)改變顯示,隱藏navigationBar之后,tableview與導(dǎo)航欄會(huì)有44像素的空白。事實(shí)說(shuō)明這樣做沒(méi)用);
3、- (CGPoint)translationInView:(nullable UIView *)view;方法的使用
4、為什么一定要設(shè)置self.navigationController.navigationBar.barTintColor=[UIColor whiteColor];屬性
5、搞清楚UIScrollView,UITableView,navigationBar的內(nèi)在聯(lián)系
然后再去看代碼。
*1、- (void)bringSubviewToFront:(UIView *)view;方法可以將指定的視圖推送到前面,
*2、UIScrollView 的contentOffset屬性的含義是:scrollview當(dāng)前顯示區(qū)域頂點(diǎn)相對(duì)于frame頂點(diǎn)的偏移量
*3、- (CGPoint)translationInView:(nullable UIView *)view;獲取到的是手指移動(dòng)后,在相對(duì)坐標(biāo)中的偏移量
*4、設(shè)置self.navigationController.navigationBar.barTintColor=[UIColor whiteColor];屬性的目的:一是方便修改導(dǎo)航欄的背景顏色,二是我們將給navigationBar添加一個(gè)UIView控件,蘋(píng)果官方文檔給的解釋是:The behavior of tintColor for bars has changed on iOS 7.0. It no longer affects the bar's background and behaves as described for the tintColor property added to UIView.To tint the bar's background, please use -barTintColor.并且這個(gè)view的背景顏色跟self.navigationController.navigationBar.barTintColor是保持一致的。
*5、UIScrollView,UITableView,navigationBar的內(nèi)在聯(lián)系:UIScrollView是UITableView的父類,而navigationBar又在UITableView上(我是這樣理解的不知道是否有錯(cuò)),所以只要將UIScrollView的contentOffset偏移量修改即可實(shí)現(xiàn)此需求。
其次,來(lái)看代碼。
自定義個(gè)NavBarViewController繼承UIViewController, NavBarViewController.h文件代碼如下:
@interface NavBarViewController : UIViewController
- (void)followSwipeScrollView:(UIView *)scrollView;
@end
NavBarViewController.m文件代碼如下:
#define NavBarFrame self.navigationController.navigationBar.frame
@interface NavBarViewController ()<UIGestureRecognizerDelegate>
@property (weak, nonatomic) UIView *scrollView;
@property (strong, nonatomic) UIPanGestureRecognizer *panGesture;
@property (strong, nonatomic) UIView *overLay;
@property (assign, nonatomic) BOOL isHidden;
@end
@implementation NavBarViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//設(shè)置navigationBar跟隨滾動(dòng)的視圖(可以是scrollView或者tableview,webview。)
-(void)followSwipeScrollView:(UIView *)scrollView
{
self.scrollView = scrollView;
self.panGesture = [[UIPanGestureRecognizer alloc] init];
self.panGesture.delegate = self;
self.panGesture.minimumNumberOfTouches = 1;
[self.panGesture addTarget:self action:@selector(handlePanGesture:)];
[self.scrollView addGestureRecognizer:self.panGesture];
self.overLay = [[UIView alloc] initWithFrame:self.navigationController.navigationBar.bounds];
self.overLay.alpha = 0;
self.overLay.backgroundColor = self.navigationController.navigationBar.barTintColor;
[self.navigationController.navigationBar addSubview:self.overLay];
[self.navigationController.navigationBar bringSubviewToFront:self.overLay];
}
#pragma mark - 兼容其他手勢(shì)
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
#pragma mark - 手勢(shì)監(jiān)聽(tīng)方法
-(void)handlePanGesture:(UIPanGestureRecognizer *)panGesture
{
CGPoint translation = [panGesture translationInView:[self.scrollView superview]];
//顯示
if (translation.y >= 5) {
if (self.isHidden) {
self.overLay.alpha = 0;
CGRect navBarFrame = NavBarFrame;
CGRect scrollViewFrame = self.scrollView.frame;
navBarFrame.origin.y = 20;
scrollViewFrame.origin.y += 44;
scrollViewFrame.size.height -= 44;
[UIView animateWithDuration:0.5 animations:^{
NavBarFrame = navBarFrame;
self.scrollView.frame = scrollViewFrame;
}];
self.isHidden = NO;
}
}
//隱藏
if (translation.y <= -20) {
if (!self.isHidden) {
CGRect frame = NavBarFrame;
CGRect scrollViewFrame = self.scrollView.frame;
frame.origin.y = -24;
scrollViewFrame.origin.y -= 44;
scrollViewFrame.size.height += 44;
[UIView animateWithDuration:0.2 animations:^{
NavBarFrame = frame;
self.scrollView.frame = scrollViewFrame;
} completion:^(BOOL finished) {
self.overLay.alpha = 1;
}];
self.isHidden = YES;
}
}
}
-(void)viewDidAppear:(BOOL)animated{
[self.navigationController.navigationBar bringSubviewToFront:self.overLay];
}
@end
最后是使用說(shuō)明:
1.將需要此效果的 UIViewController 繼承NavBarViewController;
2.調(diào)用方法 [self followRollingScrollView:self.****]; //可以是scrollView或者tableview,webview。
注意:一定要設(shè)置 self.navigationController.navigationBar.barTintColor 屬性。
(此方法的核心不是將navigationBar隱藏了,只是將UIScrollView的frame:的y值上移了,navigationBar也跟著上移了而已)
至此,要其它需要實(shí)現(xiàn)像nice這樣的navigationBar需求,只要繼承NavBarViewController設(shè)置相關(guān)屬性,實(shí)現(xiàn)相關(guān)方法即可。如有理解錯(cuò)誤請(qǐng)多多指教,希望大家能共同進(jìn)步。