這是我們最終想要得到的效果:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5yM3MTM2MTN3IDM5MDOyQTMvw1NwQDM1EDMy8CXzRWYvxGc19CXpBXYvwVbvNmLn1Waj92YuM2Yvw1LcpDc0RHaiojIsJye.gif)
思路
在UISrollView的delegate方法
1 | |
中根據目前的contentOffset更新navigationBar的backgroundColor即可,so easy~
開動
那麼我們來看看apple為我們提供了哪些API來設定navigationBar的顔色。
首先想到的是最常用的[UINavigationBar appearance],我們一般會在AppDelegate中使用它對navigationBar進行統一的設定。但是如果試一下,會發現在scrollViewDidScrollView中調用它并不能動态地改變navigationBar的顔色,原因可以看一下Apple的doc:
Use the UIAppearance protocol to get the appearance proxy for a class. You can customize the appearance of instances of a class by sending appearance modification messages to the class’s appearance proxy.
但是:
iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back.
是以換一條路,直接修改UINavigationBar的backgroudColor:
1 2 3 4 5 6 7 8 9 10 11 | |
結果卻是……
仔細觀察,會發現navigationBar的高度是44,它的上方是statusBar,而且,navigationBar的上面還有一個未知的View……到底Apple是怎麼實作UINavigationBar的呢,讓我們一探究竟!
在xcode的頂部菜單欄找到Debug > View Debugging > Capture View Hierarchy:
原來UINavigationBar上有一個_UIBackDropView,正是它決定了navigationBar的背景色。
那麼我們是不是可以修改它的顔色呢,趕緊打開UINavigationBar.h,找了一圈,
既然沒有public的API,我們隻能hack了!
Hack
我們的思路很簡單,參照Apple的實作,在navigationBar的view hierarchy中插入一個view,通過它來控制在navigationBar的backgroundColor。
考慮到繼承UINavigationBar使用起來會非常不便,我們決定用Category來實作,首先定義我們的category:
1 2 3 | |
實作:我們使用associatedObject将overlayView動态地綁定到UINavigationBar的instance上,當調用lt_setBackgroundColor的時候,我們隻要更新這個overlayView就行啦~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
最後在scrollViewDidScroll中,我們就可以動态地修改UINavigationBar的backgroundColor了:
1 | |
完整的代碼在這裡
寫在最後
UINavigationBar是一個比較特殊的view,它被系統高度內建,有時候定制起來并不那麼友善。其實這個demo完全可以用另外一種方法實作,就是不用UINavigationBar,自己畫一套UI。
很多時候我們都會發現系統原生控件出現一些預料之外的行為,那麼打開view debugging,找出原因,然後解決它!