背景
最近要做一個需求,需要把其中兩個頁面做成全屏的(無導航欄)。我把這個主要的代碼抽出來上傳到github上俘枫,導航欄demo,可點擊下載查看逮走。
主要代碼實現(xiàn)
主要思路就是在該隱藏的ViewController的ViewWillAppear里面把導航欄隱藏掉
- (void)viewWillAppear:(BOOL)animated{
? ?[super viewWillAppear:animated];
? ? BOOL hidden =YES;
? ?[self setNavigationBarHidden:hidden animated:YES];
}
然后發(fā)現(xiàn)被隱藏導航欄的頁面不能使用手勢滑動返回鸠蚪,于是就自定義一個手勢滑動返回(github上可以看到完整代碼)。
idtarget =self.navigationController.interactivePopGestureRecognizer.delegate;
UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
pan.delegate=self;
[self.view addGestureRecognizer:pan];
self.navigationController.interactivePopGestureRecognizer.enabled=NO;
然后發(fā)現(xiàn)师溅,左上角的返回按鈕不正常返回了茅信,于是自定義了一把返回按鈕
UIBarButtonItem* backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回"style:UIBarButtonItemStylePlain target:selfaction:@selector(onBackButton)];
[backItem setImage:imageWithName(@"back.png")];
//設置backBarButtonItem即可
self.navigationItem.leftBarButtonItem= backItem;
好,看起來也沒什么問題了墓臭。
bug的出現(xiàn)
直接上效果圖吧蘸鲸,由圖可知,BBB頁面的title變成了AAA的了窿锉。沒錯酌摇,導航欄錯亂了。
我們來理一下這些界面嗡载,第一個是首頁(有導航欄)窑多,第二個和第三個是沒有導航欄的,第四個是AAA有導航欄的鼻疮,第五個BBB也是有導航欄的怯伊,問題出現(xiàn)在第五個BBB頁面上琳轿。
bug的重現(xiàn)
這個bug一般情況下還不好重現(xiàn)判沟,因為它涉及的路徑比較深,經(jīng)過一次一次的嘗試崭篡,最后終于得出了它的必現(xiàn)公式:("->"表示push頁面挪哄,[]表示要執(zhí)行的操作,()表示注釋說明琉闪, => 表示得到的結果)
無導航欄頁面A->無導航欄頁面B[滑動返回迹炼,并最終停留在B頁面(實際上沒有返回)]->有導航欄頁面C->有導航欄頁面D=>頁面D導航欄異常;
bug的原因
在說原因之前颠毙,先普及一個知識斯入,在上面的頁面中,它們的導航欄是共用的蛀蜜,可以理解為一個單例刻两,導航欄里面有三個item,分別是
leftBarButtonItem滴某、rightBarButtonItem和title磅摹。這三個item是存放于棧中的滋迈,每個VC都擁有一套屬于它們的item,頁面切換時它們只是刷新了這些item户誓,而導航欄還是那個導航欄饼灿。
既然知道的重現(xiàn)路徑,那么可以找到它出現(xiàn)的原因了帝美。由于導航欄部分的代碼是不開源的赂弓,所以具體哪句代碼出了問題,我們也不好下定論盒至,我們只能根據(jù)現(xiàn)象來猜測其本質(zhì)缺谴。由必現(xiàn)公式可以得知,兩個關鍵的因素是:無導航欄和滑動返回女责。所以我的猜測是漆枚,導航欄在隱藏的情況下,連續(xù)打開兩個無導航欄的頁面抵知,滑動返回會對導航欄棧產(chǎn)生影響墙基,導致導航欄棧的錯誤;這個影響刷喜,個人猜測是和滑動返回的動畫以及隱藏導航欄的動畫有關残制。
猜測的依據(jù):
1)上面必現(xiàn)公式輔證了這一點
2)當隱藏導航欄時,系統(tǒng)是屏蔽了劃動返回手勢的掖疮,說明蘋果并不建議隱藏導航和滑動返回同時使用初茶。
3)在沒有找到它的錯誤之前先認為它是對的吧(至少根據(jù)這個猜測可以解決這個bug)。
bug的修復
知道bug的原因也是為了修復bug浊闪,根據(jù)上面的猜測恼布,我們的解決方案可以從以下三點入手:
1)不隱藏導航欄
2)不連續(xù)打開兩個無導航欄頁面
3)不用滑動返回手勢
由于需求的需要,滑動返回手勢是不能去掉的搁宾,那么只能從前兩點入手了折汞,
1、不隱藏導航欄盖腿,但是我們并不需要導航欄爽待,所以,我們只要看不到導航欄就行了翩腐,并不需要隱藏導航欄鸟款,那么,這里又有兩種方案茂卦,1)把導航欄顏色設置和背景色一樣何什,那么看起來就是全屏的了;2)把導航欄設置為透明疙筹,那看起來也是沒有了導航欄富俄。
鑒于有的頁面不是純色的禁炒,所以無法把導航欄顏色設置為和背影色一樣,不妨把導航欄設置為透明試試看能不難解決這個bug霍比。
- (void)setNavigationBarHidden:(BOOL)navigationBarHidden animated:(BOOL)animated{
_navigationBarHidden= navigationBarHidden;
self.navigationController.navigationBar.alpha = !navigationBarHidden;
}
這里把設置導航欄的hidden的方法改為設置其透明度幕袱,下面看看效果,由下圖看出悠瞬,這樣確實可以解決了這個bug们豌。
2、不連續(xù)打開兩個無導航欄頁面浅妆。我們先看看在B頁面里面滑動返回并停留在B頁面時望迎,都執(zhí)行了哪些方法,首先我們在每個生命周期的方法里面打上log
- (void)viewWillAppear:(BOOL)animated{
[superviewWillAppear:animated];
[selfWL_LOG:@"viewWillAppear"];
}
- (void)viewDidAppear:(BOOL)animated{
[superviewDidAppear:animated];
[selfWL_LOG:@"viewDidAppear"];
}
- (void)viewWillDisappear:(BOOL)animated{
[superviewWillDisappear:animated];
[selfWL_LOG:@"viewWillDisappear"];
}
- (void)viewDidDisappear:(BOOL)animated{
[superviewDidDisappear:animated];
[selfWL_LOG:@"viewDidDisappear"];
}
可以看出凌外,主要是執(zhí)行了viewWillDisappear 和 viewWillAppear方法辩尊,未了不讓它連續(xù)打開兩個無導航欄的頁面,可以可以在需要透明導航欄的頁面的viewWillAppear的方法里面添加下面的代碼
- (void)viewWillAppear:(BOOL)animated{
[superviewWillAppear:animated];BOOLhidden = !self.navigationController.navigationBarHidden;
[selfsetNavigationBarHidden:hidden animated:YES];
}
如果當前導航欄是隱藏的康辑,那么我就把它顯示出來摄欲,如果它是顯示的,那么我就把它隱藏 疮薇。這樣就可以保證不會有連續(xù)的兩個隱藏導航欄的頁面在切換了胸墙。
為了保證最后顯示的是無系統(tǒng)導航欄的,我們還需要在viewDidAppear里面添加下面方法來把導航欄隱藏了按咒。
- (void)viewDidAppear:(BOOL)animated{
[superviewDidAppear:animated];
[selfsetNavigationBarHidden:YESanimated:NO];
}
然后我們再運行一下看看效果,驗證也是OK的
注意事項
導航欄的坑的比較奇葩迟隅,所以有些細節(jié)還是要注意的
1)在viewWillAppear和ViewWillDisappear方法里面設置導航欄的隱藏屬性一定要帶動畫;
[self.navigationController setNavigationBarHidden:navigationBarHidden animated:YES];
2)在viewDidAppear里面設置導航欄隱藏屬性最好不要動畫励七;
3)盡量不要在ViewWillDisappear里面修改導航欄(你的生命周期都快結束了智袭,就別瞎折騰了);
4)每個VC管理自己的導航欄呀伙,永遠不要相信非本類的方法补履,不要以為其他VC會幫你把導航欄設置好了添坊。(比如剿另,如果當前頁面是要顯示導航欄的,那么就要乖乖地在viewWillAppear里面把導航欄顯示出來贬蛙,不要以為默認的就是顯示的雨女,很有可能上一個頁面就把它隱藏了,空間里面就遇到過這樣的bug)
若有遇到同樣問題的并無法解決的阳准,歡迎評論或私信