动态修改UINavigationBar的背景色
这是我们最终想要得到的效果:
思路
在UISrollView的delegate方法
1
|
- (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:
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,找出原因,然后解决它!
相关文章
- HIve修改表
- XCODE修改IOS应用的名称
- 银行营业网点管理系统——修改的页面(updateBreaches.jsp)
- js 动态修改页面文本字体
- File Explore 中data权限修改,实体机
- vue3: 动态修改favicon(网站的ico 图标)(vue@3.2.26)
- 修改编辑器为Markdown编辑器
- Flink实时动态修改算子规则
- Linux - 修改内核启动顺序及删除无用内核
- MySQL内核月报 2015.02-MySQL · 捉虫动态· 变量修改导致binlog错误
- golang入门:for...range修改切片中元素的值的另类方法
- 修改某个appointment已经存在的opportunity relation
- 如何动态修改SAP CRM WebClient UI表格栏的宽度
- uview——switch开关 列表修改状态
- Recovery系统的框架结构说明及常用的客制化修改流程
- Android 11.0 动态修改SystemProperties中ro开头系统属性的值
- 〖Python自动化办公篇⑤〗- 文件自动化管理 - 清理重复的文件与批量修改文件名
- MATLAB | 绘图复刻(四) | 和弦图+颜色修改+标签旋转
- C站能力认证任务关卡1-1 修改《植物大战僵尸》的存档文件,将一个新用户的进度直接修改到5-1关,金钱(能量)直接修改到10000。
- Java动态追踪技术探究(动态修改)
- 基于jsp+servlet图书管理系统之后台用户信息修改操作
- 修改CentOS6.5默认主机名(root下操作)
- macos linux vim Tab 修改为4个空格
- AD10 没有原理图是否可以修改 PCB
- 博弈型动态规划模板——精髓:把两个选手当成一个人,每次面对a[i…j]选最优解,用dfs+cache做最直观,再考虑修改为dp数组