这是咱们最终想要获得的效果: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,找出缘由,而后解决它!