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

思路

在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,找出原因,然后解决它!

动态修改UINavigationBar的背景色的更多相关文章

  1. 动态修改UINavigationBar的背景色--by-胡旭

    这是我们最终想要得到的效果 思路 在UISrollView的delegate方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView中根据当前 ...

  2. iOS 动态修改导航栏颜色 UINavigationBar

    示例 所谓动态修改  意思是 在当前页面滚动的过程中 亦或 是在 触发返回事件\进入一个新的页面  导航栏的动态变化 由于系统级别的navBar 高度集成  很多自己想实现的功能 很不好弄 如果是通过 ...

  3. 动态修改svg的颜色,svg做背景色时候修改颜色

    svg修改背景色可以使用fill属性来修改,但是我现在需要动态改变svg的颜色,例如我hover的时候 现在发现一种兼容性还不错的方法是css属性mask 类似于给路径填充上颜色,结合backgrou ...

  4. ReactNative 根据scrollView/listview滑动距离动态修改NavBar颜色

    我们常见某些APP上滑的时候,NavBar颜色会从透明渐变为某种颜色 原理非常简单,根据scrollView的回调动态修改NavBar的透明度即可. 在RN中,尤其是ListView中这个回调不是很好 ...

  5. ASP.NET中直接用C# 动态修改CSS样式

    ASP.NET中直接用C# 动态修改CSS样式  wonsoft (wonsoft@163.com) 使用JavaScript控制CSS样式有点麻烦,还是觉得直接使用C#操作更方便快捷,本文通过两个B ...

  6. 关于devexpress报表XtraReport,动态修改报表样式(.repx格式),动态添加数据并使用的理解

    一.基本概念: XtraReports 中的每个报表都由 XtraRepot 类的一个实例表示,或者由该类的子类来表示(这种情况更常见). 因此,每个报表都作为带区的容器使用,而每个带区中都包含报表控 ...

  7. 【VS开发】VS2010 MFC中控件、对话框等背景颜色动态修改的方法

    [VS开发]VS2010 MFC中控件.对话框等背景颜色动态修改的方法 标签(空格分隔):[VS开发] 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明: ...

  8. react+antd 使用脚手架动态修改主题色

    最近做了一个需求,后台管理系统添加一个可以动态修改ant-design主题色.查询了大多数的文章,发现基本都是抄来抄去,而且文章记录的也一点也不详细.刚刚把这个功能做完了,顺便记录一下如何去修改主题色 ...

  9. thinkphp 3.2.3 动态修改conf配置文件

    thinkphp 3.2.3 的C()方法能修改配置文件,但是是动态修改的,没有真正的更改文件. 我查了网上网友分享的方法,都不怎么合适,我就自己摸索写了一个,配置写到text.php中,我的目录如下 ...

随机推荐

  1. Pig系统分析(6)-从Physical Plan到MR Plan再到Hadoop Job

    从Physical Plan到Map-Reduce Plan 注:由于我们重点关注的是Pig On Spark针对RDD的运行计划,所以Pig物理运行计划之后的后端參考意义不大,这些部分主要分析流程, ...

  2. 高可用集群(HA)配置

    高可用集群(HA) 1. 准备工作 HA的心跳监测可以通过串口连接监测也可以通过网线监测,前者需要服务器有一个串口,后者需要有一个空闲网卡.HA架构中需要有一个共享的存储设备首先需要在两台机器上安装m ...

  3. nginx使用keepalived实现高可用

    环境: 主:linux-node1  110.0.0.137 备:linux-node2  110.0.0.138   VIP: 110.0.0.120   NGINX安装: # rpm -ivh h ...

  4. getAttribute()与getParameter的区别

    当两个Web组件之间为转发关系时,转发源会将要共享 request范围内的数据先用setAttribute将数据放入到HttpServletRequest对象中,然后转发目标通过 getParamet ...

  5. 本地开发时同时启动多个tomcat服务器

    1.环境变量中不要设置CATALINA_HOME: 2.分别修改安装目录下的conf子目录中的server.xml文件: a.修改http访问端口(默认为 8080端口),将8080修改为tomcat ...

  6. Oracle复杂查询

    1:列出所有员工的姓名,部门名称,和工资 select a1.ename,a1.sal,a2.dname from emp a1,dept a2 where a1.deptno = a2.deptno ...

  7. hdu 确定比赛名次

    算法:拓扑排序 题意:有一个比赛,现在知道很多队之间的关系:让你去让确定比赛排名: Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,... ...

  8. Javascript兼容收集

    1.IE6背景缓存 try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){} 2. e ...

  9. php json_encode数据格式化2种格式[]和{}

    在php中,json格式化数据后,会出现2种形式数据: 1.当array是一个从0开始的连续数组时,json_encode的结果是一个由[]括起来的字符串 $arr = array('a' , 'b' ...

  10. 元组:戴上了枷锁的列表 - 零基础入门学习Python013

    元组:戴上了枷锁的列表 让编程改变世界 Change the world by program 元组:戴上了枷锁的列表 由于和列表是近亲关系,所以元组和列表在实际使用上是非常相似的. 我们这节课主要通 ...