转自:i‘m Allen的博客

先给代码:https://github.com/allenhsu/CRNavigationController

1. 问题的表现

相信很多人在 iOS 7 的适配过程中遇到了类似这样的问题。当你试图通过设置 navigationBar.barTintColor 的时候,你陷入了一个两难的困境,假设你的预期是这样的:

设计稿

但当 navigationBar.translucent 为 YES 时,你的 navigationBar 看起来可能是这样的:

实际情况

最简单的方法是妥协地设置 translucent 为 NO,于是 navigationBar 的背景色看起来与设计稿一致了,但是设计师可能会跟你吐槽这个 navigationBar 一点也不 iOS 7,他希望 navBar 还是可以透出高斯模糊后的背景。

纵观 App Store,网易新闻和 Facebook 似乎比较好地解决了这个问题。

搜集了一些相关资料后自觉找到了不错的解决方案,于是总结成文。

2. iOS 7 中的 barTintColor

Bar color calculator for iOS7 (UIToolbar and UINavigationBar)》给出了从设计稿色值到 UIColor 的转换和逆转换公式:

假设设计稿中色值为 x(0-255),转换到 UIColor 用的色值用如下公式:

y = (x - 102) / 0.6

如果取 0-1.0(UIColor 中 RGB 的取值),对应公式:

y = (x - 0.4) / 0.6

反之:

x = 0.6 * y + 0.4

这意味着只设置 barTintColor,你得到的屏幕上结果的 RGB 值均不会小于 102(0.4),换言之,这样的颜色明度较高,无法覆盖完整的色域。但倘若你的设计稿是一个明度较高的背景色,如灰色 (102, 102, 102),那么只需设置 barTintColor 为纯黑 (0, 0, 0) 就能得到设计稿中所需的背景色,但是大多情况下这个公式无法满足需求。

注:本文所说的屏幕上的结果色值均指与白色底色叠加后的颜色,假设设计稿中色值亦是指白底叠加的情况。

3. 不完美的解决方案

Stackoverflow 上有一个解决方案,作者也在 GitHub附上了代码。这个方案在我看来并不完美,最大的缺点就是代码中输入的色值并非最终屏幕输出的色值(仍以白底为参考),仍有明显色差。这就意味着如果要实现与设计稿一致的效果,你需要通过不断地调整、取色、对比来找到一个 Magic Value。不过这个方案给出了一个很好的思路,即通过叠加一个半透明的 CALayer,来改变 navigationBar 的背景色,或者说提高背景色的明度。

4. 色彩叠加

为了减小篇幅,这里把色彩叠加简化为两色叠加,假设 c1 是当前颜色,c2 为覆盖在 c1 上面的颜色,并且透明度(alpha/opacity)为 a,那么叠加后屏幕上的颜色为 (1 - a) * c1 + a * c2。

5. 数学问题

剩下的工作就是纯数学问题了,题目是:在 2 中计算所得的颜色上叠加什么颜色和透明度的 Layer,可以得到设计稿中的原色。

假设设计稿色值为 n,传入 barTintColor 的参数也为 n(我要求的所设即所得),根据 2 中公式,navigationBar 自带的背景色为:

b1 = 0.6 * n + 0.4

设叠加的 Layer 的背景色为 n2,透明度为 a,那么叠加后得到的颜色为:

b2 = (1 - a) * b1 + a * n2

= (1 - a) * (0.6 * n + 0.4) + a * n2

我希望:

b2 = n

即:

(1 - a) * (0.6 * n + 0.4) + a * n2 = n

推导得到:

n2 = 0.4 * n / a + 0. 6 * x + 0.4 - 0.4 / a

为了保证 n2 > 0,可以得到:

a > (0.4 - 0.4 * n) / (0.6 * n + 0.4)

就是说为了实现部分较深的颜色,a 不得不取较高的值,也就意味着 navBar 的通透度可能会适当降低,例如网易红的例子中,a 大概在 0.78 左右,所以看起来不那么通透。

该不等式的右边是个递减函数,所以取色值 RGB 中的最小值来计算右式最大值从而得到 a 的最小值,该步对应代码中的:

  1. CGFloat minVal = MIN(MIN(red, green), blue);

  2. if

    ([self convertValue:minVal withOpacity:opacity] < 0) {

  3. opacity = [self minOpacityForValue:minVal];

  4. }

  5. 在得到 a 即 opacity 的值后,通过以下代码计算得到叠加的 Layer 的色值:

  6. - (CGFloat)convertValue:(CGFloat)value withOpacity:(CGFloat)opacity

  7. {

  8. return

    0.4 * value / opacity + 0.6 * value - 0.4 / opacity + 0.4;

  9. }

综上,这样计算出来的叠加层的背景色和透明度可以使得叠加后的结果正好与设计稿的色值一致,至此很好地解决了 iOS 7 中 navigationBar 的 barTintColor 的适配问题,该方法同样适用于解决 UIToolBar 和 UITabBar 的背景色的适配。

最后附上 GitHub 地址:https://github.com/allenhsu/CRNavigationController 样例中,Red 为网易红,Blue 为脸书蓝,自行测试效果。

来源:http://news.ipadown.com/30103

<转>如何在iOS 7中设置barTintColor实现类似网易和 Facebook 的 navigationBar 效果的更多相关文章

  1. 如何在IOS开发中在自己的framework中添加.bunble文件

    今天就跟大家介绍一下有关,如何在IOS开发中在自己的framework中添加.bunble文件,该文章我已经在IOS教程网(http://ios.662p.com)发布过来,个人觉得还是对大家有帮助的 ...

  2. 转 如何在IOS设备中去掉屏幕上的status bar

    引入如何在IOS设备中去掉屏幕上的status bar,即:不显示设备上方的[网络.时间.电池??]条?操作方法一:在-info.list项目文件中,加上“Status bar is initiall ...

  3. 如何在iOS设备中配置S/MIME邮件签名证书

    本篇将介绍如何在iOS设备(如iPhone或iPad)上导入.配置并使用S/MIME邮件证书. 前置条件: iOS设备上已完成邮箱账号配置: 您的S/MIME邮件证书PFX/P12文件已导出备用. 步 ...

  4. iOS开发中设置UITextField的占位文字的颜色,和光标的颜色

    在iOS开发中,对于很多初学者而言,很有可能碰到需要修改UITextField的占位文字的颜色,以及当UITextField成为第一响应者后光标的颜色,那么下面小编就介绍一下修改占位文字和光标的颜色. ...

  5. 如何在 iOS 8 中使用 Swift 实现本地通知(下)

    在上集中,我们已经构建了一个简单的待办列表应用(to-do list app),这个应用可以在待办项过期时通过本地通知提醒用户.现在,我们要在之前的基础上添加以下功能:应用图标角标上显示过期待办项的数 ...

  6. IOS开发—IOS 8 中设置applicationIconBadgeNumber和消息推送

    摘要 在IOS7中设置applicationIconBadgeNumber不会有什么问题,但是直接在IOS8中设置applicationIconBadgeNumber会报错 因为在IOS8中要想设置a ...

  7. 【转】IOS开发—IOS 8 中设置applicationIconBadgeNumber和消息推送

    在IOS7中设置applicationIconBadgeNumber不会有什么问题,但是直接在IOS8中设置applicationIconBadgeNumber会报错 因为在IOS8中要想设置appl ...

  8. 为何在font-family属性中设置多个值

    通常前端开发中会对body标签中设置font-family属性多个值,例如: body{padding:0;margin:0;font-size:12px;text-align:left;font-f ...

  9. IOS开发中设置控件内容对齐方式时容易混淆的几个属性

    IOS开发中四个容易混淆的属性: 1. textAligment : 文字的水平方向的对齐方式 1> 取值 NSTextAlignmentLeft      = 0,    // 左对齐 NST ...

随机推荐

  1. 登录ssh时Host key verification failed错误

    工作中总是测试不同的路由设备, 路由器的ip都是 192.168.111.1 ,ssh登录的时候总是出现这个错误. macos上,错误如下 spawn ssh -p 22 root@192.168.1 ...

  2. 【Unity Shaders】Shader学习资源和Surface Shader概述

    写在前面 写这篇文章的时候,我断断续续学习Unity Shader半年了,其实还是个门外汉.我也能体会很多童鞋那种想要学好Shader却无从下手的感觉.在这个期间,我找到一些学习Shader的教程以及 ...

  3. (NO.00004)iOS实现打砖块游戏(六):反弹棒类

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 打砖块游戏另一个要素是反弹棒,我们在这篇类来实现反弹棒类. 创建 ...

  4. ROS(indigo)机器人操作系统学习有趣丰富的Gazebo仿真示例evarobot

    一直在寻找一个示例可以将ROS学习中常用的基础内容大部分都包含进去,最好还包括Gazebo仿真, 这样即使没有硬件设备,也可以很好的学习ROS相关内容,但又必须有对应的硬件,便于后续研究. 这里,介绍 ...

  5. Eclipse下载GitHub源码

    1. 可以通过Eclipse->File->Import->Project from Git->URI来提取工程   2. 也可以通过打开git仓库视图(Eclipse 自带了 ...

  6. Java实现栈之计算器

    Java实现栈来做一个将中缀表达式转化为后缀表达式的程序,中缀表达式更符合我们的主观感受,后缀表达式更适合计算机的运算,下面直接上代码吧: package Character1; import jav ...

  7. EBS Concurrent Manager(并发管理器)异常处理[final]

    来自:http://blog.itpub.net/35489/viewspace-742191/ 有时候我们在通过 adstpall.sh 关闭应用后,然后再使用adstrtal.sh开启.发现并发 ...

  8. 采用JSP+JavaBean的方式进行简单的实现用户的网页登陆实例

    我们都知道J2EE中的Model1开发模式,那么下面就让我们一起简单的进行一下回顾,其主要是体现了一个初步的分层的思想: jsp层,业务逻辑层,以及我们的数据库层,主要的作用分别为,jsp层负责与用户 ...

  9. 【算法导论】单源最短路径之Bellman-Ford算法

    单源最短路径指的是从一个顶点到其它顶点的具有最小权值的路径.我们之前提到的广度优先搜索算法就是一种无权图上执行的最短路径算法,即在所有的边都具有单位权值的图的一种算法.单源最短路径算法可以解决图中任意 ...

  10. Mahout系列之----kmeans 聚类

    Kmeans是最经典的聚类算法之一,它的优美简单.快速高效被广泛使用. Kmeans算法描述 输入:簇的数目k:包含n个对象的数据集D. 输出:k个簇的集合. 方法: 从D中任意选择k个对象作为初始簇 ...