這是咱們最終想要獲得的效果:ios
思路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];
}
}
|
結果倒是……
仔細觀察,會發現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
|
@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,找出緣由,而後解決它!