这是我们最终想要得到的效果

思路

UISrollView的delegate方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView中根据当前的contentOffset更新navigationBar的backgroundColor即可,so easy~

开动

那么我们来看看apple为我们提供了哪些API来设置navigationBar的颜色。

首先想到的是最常用的[UINavigationBar appearance],我们一般会在AppDelegate中使用它对navigationBar进行统一的设置。但是如果试一下,会发现在scrollViewDidScrollView中调用它并不能动态地改变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:

结果却是。。。

仔细观察,会发现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:

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

实现:我们使用associatedObject将overlayView动态地绑定到UINavigationBar的instance上,当调用lt_setBackgroundColor的时候,我们只要更新这个overlayView就行啦~

@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]; // insert an overlay into the view hierarchy
self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, self.bounds.size.height + 20)];
self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; [self insertSubview:self.overlay atIndex:0];
}
self.overlay.backgroundColor = backgroundColor;
}
@end

最后在scrollViewDidScroll中,我们就可以动态地修改UINavigationBar的backgroundColor了:

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

完整的代码在这里:https://github.com/ltebean/LTNavigationBar

写在最后

UINavigationBar是一个比较特殊的view,它被系统高度集成,有时候定制起来并不那么方便。其实这个demo完全可以用另外一种方法实现,就是不用UINavigationBar,自己画一套UI。

很多时候我们都会发现系统原生控件出现一些预料之外的行为,那么打开view debugging,找出原因,然后解决它!

最新文章

  1. 51nod1102(数塔)
  2. linux作业
  3. iOS 安装Cocoapods以及安装第三方库的操作流程
  4. golang——channel笔记
  5. bzoj2515 Room
  6. Java Web 工作技巧总结 16.8
  7. (转)JS浮动窗口(随浏览器滚动而滚动)
  8. C++学习33 函数模板
  9. 备份了一个nginx的虚拟主机配置文件报错
  10. JS、C# 去除html标签
  11. cdn加速对门户网站产生的影响
  12. 菜鸟脱壳之脱壳的基础知识(四)——利用ESP定律来寻找OEP
  13. HDU 5391 Zball in Tina Town【威尔逊定理】
  14. 学习 rostopic
  15. Windows下使用MakeFile(Mingw)文件
  16. C/C++ 移位计算代替乘除运算
  17. Openfire 服务器更换ip后的恢复方法
  18. 关于使用modelsim的一点感想
  19. 【转】jmeter入门教程- Jmeter教程及技巧汇总
  20. 59、佳博wifi打印机怎么配置

热门文章

  1. 美和易思 MOOT去鼠标检测,快进,倍速,自动下一章
  2. 每天学一点——python变量、常量与数字类型
  3. 什么是UE模型?
  4. 初识python: 类练习 - 老板&员工
  5. 华为云 Kubernetes 管理员实训 四 课后作业
  6. vue 前进刷新后退不刷新
  7. Flowable实战(四)BPMN2.0 启动与结束事件
  8. 【Java】包装类
  9. python基本数据类型与操作
  10. 如何让 Hexo 在服务器稳定运行