為什么setBarTintColor顏色比原顏色淺
最簡單答案: 這是由於半透明模糊引起的 [self.navigationBar setTranslucent:NO];
但是================================================= 但是
轉自:
i‘m Allen的博客
1. 問題的表現
相信很多人在 iOS 7 的適配過程中遇到了類似這樣的問題。當你試圖通過設置 navigationBar.barTintColor 的時候,你陷入了一個兩難的困境,假設你的預期是這樣的:
設計稿
但當 navigationBar.translucent 為 YES 時,你的 navigationBar 看起來可能是這樣的:
實際情況
最簡單的方法是妥協地設置 translucent 為 NO,於是 navigationBar 的背景色看起來與設計稿一致了,但是設計師可能會跟你吐槽這個 navigationBar 一點也不 iOS 7,他希望 navBar 還是可以透出高斯模糊后的背景。
搜集了一些相關資料后自覺找到了不錯的解決方案,於是總結成文。
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 的最小值,該步對應代碼中的:
- CGFloat minVal = MIN(MIN(red, green), blue);
- if ([self convertValue:minVal withOpacity:opacity] < 0) {
- opacity = [self minOpacityForValue:minVal];
- }
- 在得到 a 即 opacity 的值后,通過以下代碼計算得到疊加的 Layer 的色值:
- - (CGFloat)convertValue:(CGFloat)value withOpacity:(CGFloat)opacity
- {
- return 0.4 * value / opacity + 0.6 * value - 0.4 / opacity + 0.4;
- }
綜上,這樣計算出來的疊加層的背景色和透明度可以使得疊加后的結果正好與設計稿的色值一致,至此很好地解決了 iOS 7 中 navigationBar 的 barTintColor 的適配問題,該方法同樣適用於解決 UIToolBar 和 UITabBar 的背景色的適配。
最后附上 GitHub 地址:
https://github.com/allenhsu/CRNavigationController 樣例中,Red 為網易紅,Blue 為臉書藍,自行測試效果。
