分析Android多主題顏色的相關(guān)問題
如果您通過以下的代碼來獲取定義的顏色值
context.getResources().getColor(R.color.some_color_resource_id);
在 Android Studio 中會有一個(gè) lint 警告,提示您 Resources#getColor(int)
在 Marshmallow
中被廢棄了,建議使用主題可知的 Resources#getColor(int, Theme
) 函數(shù)。 為了避免該警告,則可以使用 ContextCompat
:
ContextCompat.getColor(context, R.color.some_color_resource_id);
該函數(shù)的實(shí)現(xiàn)是這樣的:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return context.getResources().getColor(id, context.getTheme()); } else { return context.getResources().getColor(id); }
看起來很簡單。但是為什么會這樣呢? 為什么會開始使用帶主題的函數(shù)而廢棄之前的函數(shù)呢?
Resources#getColor(int) & Resources#getColorStateList(int) 的問題
首先來看看這兩個(gè)被廢棄的函數(shù)是干啥的:
– Resources#getColor(int)
返回一個(gè)資源 id 對應(yīng)的顏色值,如果該資源為 ColorStateList
則返回 ColorStateList
的默認(rèn)顏色值
– Resources#getColorStateList(int)
返回對應(yīng)的 ColorStateList
上面的代碼在什么情況下會破壞我的代碼呢?
要理解為何廢棄這兩個(gè)函數(shù),來看個(gè) ColorStateList 的例子。 當(dāng)在 TextView 中使用自定義的 ColorStateList 的時(shí)候, TextView 不可用狀態(tài)和可用狀態(tài)的文字顏色分別使用 R.attr.colorAccent
和 R.attr.colorPrimary
表示。
XHTML
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="?attr/colorAccent" android:state_enabled="false"/> <item android:color="?attr/colorPrimary"/> </selector>
現(xiàn)在如果您通過如下的代碼來獲取這個(gè)ColorStateList
ColorStateList csl = context.getResources().getColorStateList(R.color.button_text_csl);
上面的代碼會拋出一個(gè)異常(查看logcat 可以看到如下的信息)
W/Resources: ColorStateList color/button_text_csl has unresolved theme attributes! Consider using Resources.getColorStateList(int, Theme) or Context.getColorStateList(int) at android.content.res.Resources.getColorStateList(Resources.java:1011) ...
哪里出錯(cuò)了呢?
問題的根源在于 Resources
對象并沒有和一個(gè) Theme
對象關(guān)聯(lián),當(dāng)使用 R.attr.colorAccent
和 R.attr.colorPrimary
指代顏色的時(shí)候,在代碼中通過上面的函數(shù)解析的時(shí)候沒有指定對應(yīng)的 Theme導(dǎo)致無法解析出結(jié)果。 所以在 Marshmallow
中添加了 ColorStateList
對 Theme 的支持并且添加了這兩個(gè)新的函數(shù):Resources#getColor(int, Theme)
和 Resources#getColorStateList(int, Theme),
并使用 Theme 參數(shù)來解析里面的 attributes
屬性。
在新版本的 Support 庫中也有對應(yīng)的實(shí)現(xiàn),分別位于 ResourcesCompat
和 ContextCompat
類中。
如何解決該問題呢?
使用 AppCompat v24+ 版本可以很容易的解決該問題。
ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.button_text_csl);
在 23+ 版本上直接使用系統(tǒng)的函數(shù),在之前的版本上 AppCompat 自己解析這些 xml 文件從里面提取 attr 屬性指代的數(shù)值。 AppCompat 同時(shí)還支持 ColorStateList 新的 android:alpha
屬性。
Resources#getDrawable(int) 的問題
Resources#getDrawable(int)
和前面的兩個(gè)函數(shù)的問題是類似的。 在 Lollipop 之前的版本中無法支持 Theme attr 。
為啥我這樣用也沒有出現(xiàn)異常呢?
異常并不總是會出現(xiàn)。
VectorDrawableCompat
和 AnimatedVectorDrawableCompat
類中添加了和 AppCompatResources
類類似的功能。比如在 矢量圖中你可以使用 ?attr/colorControlNormal
來設(shè)置矢量圖的顏色,VectorDrawableCompat
會自動完成解析該 屬性的工作:
XHTML
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0" android:tint="?attr/colorControlNormal"> <path android:pathData="..." android:fillColor="@android:color/white"/> </vector>
小測試
下面使用一個(gè)小測試來回顧一下前面介紹的內(nèi)容。 假設(shè)有下面一個(gè) ColorStateList:
XHTML
<!-- res/colors/button_text_csl.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="?attr/colorAccent" android:state_enabled="false"/> <item android:color="?attr/colorPrimary"/> </selector>
在應(yīng)用中定義了如下的 Theme:
XHTML
<!-- res/values/themes.xml --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/vanillared500</item> <item name="colorPrimaryDark">@color/vanillared700</item> <item name="colorAccent">@color/googgreen500</item> </style> <style name="CustomButtonTheme" parent="ThemeOverlay.AppCompat.Light"> <item name="colorPrimary">@color/brown500</item> <item name="colorAccent">@color/yellow900</item> </style>
在代碼中有如下的函數(shù)用來解析顏色值并在代碼中創(chuàng)建 ColorStateList:
@ColorInt private static int getThemeAttrColor(Context context, @AttrRes int colorAttr) { TypedArray array = context.obtainStyledAttributes(null, new int[]{colorAttr}); try { return array.getColor(0, 0); } finally { array.recycle(); } } private static ColorStateList createColorStateList(Context context) { return new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_enabled}, // Disabled state. StateSet.WILD_CARD, // Enabled state. }, new int[]{ getThemeAttrColor(context, R.attr.colorAccent), // Disabled state. getThemeAttrColor(context, R.attr.colorPrimary), // Enabled state. }); }
看看是否能猜出在 API 19 和 API 23 版本上文字禁用狀態(tài)和正常狀態(tài)的顏色,實(shí)現(xiàn)代碼如下(5和8的情況,在TextView xml 中指定了 android:theme=”@style/CustomButtonTheme”
):
Resources res = ctx.getResources(); // (1) int deprecatedTextColor = res.getColor(R.color.button_text_csl); button1.setTextColor(deprecatedTextColor); // (2) ColorStateList deprecatedTextCsl = res.getColorStateList(R.color.button_text_csl); button2.setTextColor(deprecatedTextCsl); // (3) int textColorXml = AppCompatResources.getColorStateList(ctx, R.color.button_text_csl).getDefaultColor(); button3.setTextColor(textColorXml); // (4) ColorStateList textCslXml = AppCompatResources.getColorStateList(ctx, R.color.button_text_csl); button4.setTextColor(textCslXml); // (5) Context themedCtx = button5.getContext(); ColorStateList textCslXmlWithCustomTheme = AppCompatResources.getColorStateList(themedCtx, R.color.button_text_csl); button5.setTextColor(textCslXmlWithCustomTheme); // (6) int textColorJava = getThemeAttrColor(ctx, R.attr.colorPrimary); button6.setTextColor(textColorJava); // (7) ColorStateList textCslJava = createColorStateList(ctx); button7.setTextColor(textCslJava); // (8) Context themedCtx = button8.getContext(); ColorStateList textCslJavaWithCustomTheme = createColorStateList(themedCtx); button8.setTextColor(textCslJavaWithCustomTheme);
下面是對應(yīng)的實(shí)現(xiàn)截圖:
總結(jié)
以上就是關(guān)于分析Android多主題顏色的相關(guān)問題的全部內(nèi)容,希望本文的內(nèi)容對大家開發(fā)Android能有所幫助。
- Android主題切換之探究白天和夜間模式
- 基于android樣式與主題(style&theme)的詳解
- Android中應(yīng)用界面主題Theme使用方法和頁面定時(shí)跳轉(zhuǎn)應(yīng)用
- Android 設(shè)置主題實(shí)現(xiàn)點(diǎn)擊波紋效果的示例
- Android入門教程之創(chuàng)建樣式與主題
- Android編程應(yīng)用風(fēng)格和主題詳解
- android仿iphone主題效果的主菜單
- Android實(shí)現(xiàn)換膚的兩種思路分析
- Android編程實(shí)現(xiàn)換膚功能實(shí)例
- Android開發(fā)實(shí)現(xiàn)切換主題及換膚功能示例
相關(guān)文章
Android實(shí)現(xiàn)Listview異步加載網(wǎng)絡(luò)圖片并動態(tài)更新的方法
這篇文章主要介紹了Android實(shí)現(xiàn)Listview異步加載網(wǎng)絡(luò)圖片并動態(tài)更新的方法,結(jié)合實(shí)例形式詳細(xì)分析了ListView異步加載數(shù)據(jù)的操作步驟與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-08-08Android7.0行為變更之適配File Provider的方法
這篇文章主要介紹了Android7.0行為變更之適配File Provider的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04Android實(shí)現(xiàn)多參數(shù)文件和數(shù)據(jù)上傳
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多參數(shù)文件和數(shù)據(jù)上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12