動態修改UINavigationBar的背景色

git:https://github.com/ltebean/LTNavigationBar

動態修改UINavigationBar的背景色

2015-04-09 09:10 編輯: suiling 分類:iOS開發 來源:Glow 技術團隊博客
 3  1472

這是咱們最終想要獲得的效果:ios

1428390275361373.gif

思路git

在UISrollView的delegate方法github

1
  - (void)scrollViewDidScroll:(UIScrollView *)scrollView

中根據當前的contentOffset更新navigationBar的backgroundColor便可,so easy~xcode

開動安全

那麼咱們來看看apple爲咱們提供了哪些API來設置navigationBar的顏色。app

首先想到的是最經常使用的[UINavigationBar appearance],咱們通常會在AppDelegate中使用它對navigationBar進行統一的設置。可是若是試一下,會發如今scrollViewDidScrollView中調用它並不能動態地改變navigationBar的顏色,緣由能夠看一下Apple的doc:ui

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.加密

可是:spa

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
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
     UIColor *color = [UIColor blueColor];
     CGFloat offsetY = scrollView.contentOffset.y;
     if  (offsetY > 0) {
         CGFloat alpha = 1 - ((64 - offsetY) / 64);
         self.navigationController.navigationBar.backgroundColor = [color colorWithAlphaComponent:alpha];
     else  {
          self.navigationController.navigationBar.backgroundColor = [color colorWithAlphaComponent:0];
     }
}

結果倒是…… 

2.jpg

仔細觀察,會發現navigationBar的高度是44,它的上方是statusBar,並且,navigationBar的上面還有一個未知的View……到底Apple是怎麼實現UINavigationBar的呢,讓咱們一探究竟!

在xcode的頂部菜單欄找到Debug > View Debugging > Capture View Hierarchy:

1428390599183114.jpg

1428390603214036.jpg

原來UINavigationBar上有一個_UIBackDropView,正是它決定了navigationBar的背景色。

那麼咱們是否是能夠修改它的顏色呢,趕忙打開UINavigationBar.h,找了一圈,1428390838630372.jpg

既然沒有public的API,咱們只能hack了!

Hack

咱們的思路很簡單,參照Apple的實現,在navigationBar的view hierarchy中插入一個view,經過它來控制在navigationBar的backgroundColor。

考慮到繼承UINavigationBar使用起來會很是不便,咱們決定用Category來實現,首先定義咱們的category:

1
2
3
@interface UINavigationBar (BackgroundColor)
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor;
@end

實現:咱們使用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
@implementation UINavigationBar (BackgroundColor)static char overlayKey;
 
- (UIView *)overlay
{     return  objc_getAssociatedObject(self, &overlayKey);
}
 
- (void)setOverlay:(UIView *)overlay
{
     objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
 
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor
{     if  (!self.overlay) {
         [self setBackgroundImage:[UIImage  new ] forBarMetrics:UIBarMetricsDefault];
         [self setShadowImage:[UIImage  new ]];         // insert an overlay into the view hierarchy
         self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, 64)];
         [self insertSubview:self.overlay atIndex:0];
     }    self.overlay.backgroundColor = backgroundColor;
}@end

最後在scrollViewDidScroll中,咱們就能夠動態地修改UINavigationBar的backgroundColor了:

1
[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];

完整的代碼在這裏

寫在最後

UINavigationBar是一個比較特殊的view,它被系統高度集成,有時候定製起來並不那麼方便。其實這個demo徹底能夠用另一種方法實現,就是不用UINavigationBar,本身畫一套UI。

不少時候咱們都會發現系統原生控件出現一些預料以外的行爲,那麼打開view debugging,找出緣由,而後解決它!

相關文章
相關標籤/搜索