动态修改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,找出原因,然后解决它!

时间: 2024-12-09 10:00:39

动态修改UINavigationBar的背景色(转载)的相关文章

动态修改UINavigationBar的背景色

这是我们最终想要得到的效果: 思路 在UISrollView的delegate方法 1  - (void)scrollViewDidScroll:(UIScrollView *)scrollView 中根据当前的contentOffset更新navigationBar的backgroundColor即可,so easy~ 开动 那么我们来看看apple为我们提供了哪些API来设置navigationBar的颜色. 首先想到的是最常用的[UINavigationBar appearance],我们

动态修改UINavigationBar的背景色--by-胡 xu

这是我们最终想要得到的效果 思路 在UISrollView的delegate方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView中根据当前的contentOffset更新navigationBar的backgroundColor即可,so easy~ 开动 那么我们来看看apple为我们提供了哪些API来设置navigationBar的颜色. 首先想到的是最常用的[UINavigationBar appearance],我们一般会在A

动态修改 NodeJS 程序中的变量值

如果一个 NodeJS 进程正在运行,有办法修改程序中的变量值么?答案是:通过 V8 的 Debugger 接口可以!本文将详细介绍实现步骤. 启动一个 HTTP Server 用简单的 Hello World 做例子吧,不过略作修改.在 global 下放一个变量 message, 然后打印出来: // message content will be modified ! global.message = "hello world!"; var server = require('h

[SAP ABAP开发技术总结]动态修改选择屏幕

声明:原创作品,转载时请注明文章来自SAP师太博客,并以超链接形式标明文章原始出处,否则将追究法律责任!原文出自: 12.16.             动态修改屏幕 选择屏幕.对话屏幕都有对应的SCREEN内表,下面是几个重要属性: NAME:Name of the screen field.如果参数是select-options类型参数,则参数名以LOW与HIGH后缀来区分. GROUP1:选择屏幕元素通过 MODIF ID 选项设置GROUP1(对话屏幕通过属性设置),将屏幕元素分为一组,

动态修改spine动画渲染层次

在unity中做2D游戏开发的时候我们使用sprite比较多,sprite的层次修改我们手动修改sprite renderer下面的Order in Layer属性就行了.也可以动态的获取它的层次属性进行修改,那么怎么动态修改spine动画的层次呢,如下:   我们创建spine动画的时候,在这个物体上会有一个Mesh Renderer的组件.我们通过他来改变Skeleton Animation中的Order in Layer的值.--------------------- void Start

动态修改类注解(赋值)

1. 动态修改注解元凶: Java代码 /**  * 对象池工具类  *   * 目前提供ORM动态映射解决方案  *   * @author andy.zheng  * @since 2012.09.25 15:55 PM  * @vesion 1.0  *   */ public class ClassPoolUtils {                  /**      * 运行时动态ORM表映射      *       *       * @param entityClassNam

js 动态修改css文件

_.find(document.styleSheets[4].cssRules,function(cssRule){ if(cssRule.selectorText && cssRule.selectorText.indexOf(".navbar-fixed-top2")>-1){ cssRule.style.position=""; cssRule.style.top = "0px"; } if(cssRule.selec

js 动态修改属性值 动态修改图片,字等

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <meta http-equiv = "content-type" content="text/html;charset=utf-8"/> &

Quartz总结(四):动态修改定时器二

前文:http://www.cnblogs.com/LiuChunfu/p/5598806.html 提到了一种动态修改定时器的方法, 其本质就是在job方法中注入Schedular的对象,从Schedular中获取Trigger(触发器),然后修改触发器的条件,重新启动. 前文中的方法,其实已经涉及到了循环调用. Job类 => Job => Trigger => Schedular =>Job类. 这样是很容易发生问题的,也确实在实际项目中发生了问题,特别是当Schedular