07 APRIL 2015onios,objc,uinavigationbar
這是我們最終想要得到的效果:
思路
在UISrollView的delegate方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView中根據(jù)當(dāng)前的contentOffset更新navigationBar的backgroundColor即可亲澡,so easy~
開動(dòng)
那么我們來看看apple為我們提供了哪些API來設(shè)置navigationBar的顏色贫堰。
首先想到的是最常用的[UINavigationBar appearance],我們一般會(huì)在AppDelegate中使用它對(duì)navigationBar進(jìn)行統(tǒng)一的設(shè)置。但是如果試一下照藻,會(huì)發(fā)現(xiàn)在scrollViewDidScrollView中調(diào)用它并不能動(dòng)態(tài)地改變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:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView{UIColor*color = [UIColorblueColor];CGFloatoffsetY = scrollView.contentOffset.y;if(offsetY >0) {CGFloatalpha =1- ((64- offsetY) /64);self.navigationController.navigationBar.backgroundColor= [color colorWithAlphaComponent:alpha];? ? }else{self.navigationController.navigationBar.backgroundColor= [color colorWithAlphaComponent:0];? ? }}
結(jié)果卻是条霜。催什。。
仔細(xì)觀察宰睡,會(huì)發(fā)現(xiàn)navigationBar的高度是44蒲凶,它的上方是statusBar,而且拆内,navigationBar的上面還有一個(gè)未知的View旋圆。。麸恍。到底Apple是怎么實(shí)現(xiàn)UINavigationBar的呢灵巧,讓我們一探究竟搀矫!
在xcode的頂部菜單欄找到Debug > View Debugging > Capture View Hierarchy:
原來UINavigationBar上有一個(gè)_UIBackDropView,正是它決定了navigationBar的背景色刻肄。
那么我們是不是可以修改它的顏色呢瓤球,趕緊打開UINavigationBar.h,找了一圈敏弃,??
既然沒有public的API卦羡,我們只能hack了!
Hack
我們的思路很簡(jiǎn)單麦到,參照Apple的實(shí)現(xiàn)绿饵,在navigationBar的view hierarchy中插入一個(gè)view,通過它來控制在navigationBar的backgroundColor隅要。
考慮到繼承UINavigationBar使用起來會(huì)非常不便蝴罪,我們決定用Category來實(shí)現(xiàn),首先定義我們的category:
@interfaceUINavigationBar(BackgroundColor)- (void)lt_setBackgroundColor:(UIColor*)backgroundColor;@end
實(shí)現(xiàn):我們使用associatedObject將overlayView動(dòng)態(tài)地綁定到UINavigationBar的instance上步清,當(dāng)調(diào)用lt_setBackgroundColor的時(shí)候要门,我們只要更新這個(gè)overlayView就行啦~
@implementationUINavigationBar(BackgroundColor)staticcharoverlayKey;- (UIView*)overlay{returnobjc_getAssociatedObject(self, &overlayKey);}- (void)setOverlay:(UIView*)overlay{? ? objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (void)lt_setBackgroundColor:(UIColor*)backgroundColor{if(!self.overlay) {? ? ? ? [selfsetBackgroundImage:[UIImagenew] forBarMetrics:UIBarMetricsDefault];? ? ? ? [selfsetShadowImage:[UIImagenew]];// insert an overlay into the view hierarchyself.overlay= [[UIViewalloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width,64)];? ? ? ? [selfinsertSubview:self.overlayatIndex:0];? ? }self.overlay.backgroundColor= backgroundColor;}@end
最后在scrollViewDidScroll中,我們就可以動(dòng)態(tài)地修改UINavigationBar的backgroundColor了:
[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];
完整的代碼在這里:https://github.com/ltebean/LTNavigationBar
寫在最后
UINavigationBar是一個(gè)比較特殊的view廓啊,它被系統(tǒng)高度集成欢搜,有時(shí)候定制起來并不那么方便。其實(shí)這個(gè)demo完全可以用另外一種方法實(shí)現(xiàn)谴轮,就是不用UINavigationBar炒瘟,自己畫一套UI。
很多時(shí)候我們都會(huì)發(fā)現(xiàn)系統(tǒng)原生控件出現(xiàn)一些預(yù)料之外的行為第步,那么打開view debugging疮装,找出原因,然后解決它粘都!
Readmore postsby this author.
Share this post