首先我们想到的肯定是在UISrollView的delegate方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
根据当前的contentOffset
更新navigationBar的backgroundColor即可.
首先想到的是最常用的[UINavigationBar appearance]
,我们一般会在AppDelegate中使用它对navigationBar进行统一的设置。但是如果试一下,会发现在scrollViewDidScrollView
中调用它并不能动态地改变navigationBar的颜色,原因是: iOS应用出现变化时,视图会进入一个窗口,它不能改变已经再一个窗口的外观。
我们换一个方法试试看,直接修改UINavigationBar的backgroudColor:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UIColor *color = [UIColor redColor];
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];
}
}
然后发现,怎么是。。。。。有一半咋没有颜色 ????这是神马情况???
通过reveal查看其中的层级结构,发现NavigationBar上面有一个_UINavigationBarBackground的遮盖,正是它决定了navigationBar的背景色。
那我们把这个view拿到,删除不就可以了么?继续尝试。
我们通过打印 self.navigationController.navigationBar.subviews
看到navigationBar上有两个子控件。
"<_UINavigationBarBackground: 0x7fed90f43990; frame = (0 -20; 414 64); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = >" ,
"<_UINavigationBarBackIndicatorView: 0x7fed90d053f0; frame = (0 11.6667; 13 21); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = >"
我们可以通过遍历把 _UINavigationBarBackground
拿到并删除即可
for (UIView *view in self.navigationController.navigationBar.subviews) {
if ([view isKindOfClass:NSClassFromString(@"_UINavigationBarBackground")]) {
[view removeFromSuperview];
}
}
然后发现这样就可以了,不过状态栏还是白色的啊~~~
这时我们改变下状态栏的颜色就好了,要修改状态栏的颜色比较麻烦,那我们可以直接在navigationBar上加上一层遮罩就好
UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width,20)];
overlay.backgroundColor = [UIColor redColor];
[self.navigationController.navigationBar insertSubview:overlay atIndex:0];
不过这么干的话,那就要修改两个控件颜色。。。。这样修改起来非常的麻烦,有没有什么好点的方法呢????
考虑到继承UINavigationBar使用起来会非常不便,我们决定用Category来实现,首先定义我们的category:
@interface UINavigationBar (BackgroundColor)
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor;
@end
我们可以使用associatedObject将overlay动态地绑定到UINavigationBar的instance上,当调用lt_setBackgroundColor的时候,我们只要更新这个overlay就可以了
static char overlayKey;
@implementation UINavigationBar (BackgroundColor)
- (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]];
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了:
[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];
这个方法是参考了 LTNavigationBar
第三方类库,这类库已经给我们封装好了这些方法,使用起来非常简单