context.getResources().getColor(R.color.some_color_resource_id);在 Android Studio 中会有一个 lint 警告,提示您
Resources#getColor(int)
在 Marshmallow
中被废弃了,建议使用主题可知的 Resources#getColor(int, Theme
) 函数。 为了避免该警告,则可以使用 ContextCompat
:ContextCompat.getColor(context, R.color.some_color_resource_id);该函数的实现是这样的:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return context.getResources().getColor(id, context.getTheme());} else { return context.getResources().getColor(id);}看起来很简单。但是为什么会这样呢? 为什么会开始使用带主题的函数而废弃之前的函数呢?
Resources#getColor(int)
返回一个资源 id 对应的颜色值,如果该资源为 ColorStateList
则返回 ColorStateList
的默认颜色值 Resources#getColorStateList(int)
返回对应的 ColorStateList
R.attr.colorAccent
和 R.attr.colorPrimary
表示。<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>现在如果您通过如下的代码来获取这个
ColorStateList
ColorStateList csl = context.getResources().getColorStateList(R.color.button_text_csl);上面的代码会抛出一个异常(查看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)...哪里出错了呢?
Resources
对象并没有和一个 Theme
对象关联,当使用 R.attr.colorAccent
和 R.attr.colorPrimary
指代颜色的时候,在代码中通过上面的函数解析的时候没有指定对应的 Theme导致无法解析出结果。 所以在 Marshmallow
中添加了 ColorStateList
对 Theme 的支持并且添加了这两个新的函数:Resources#getColor(int, Theme)
和 Resources#getColorStateList(int, Theme),
并使用 Theme 参数来解析里面的 attributes
属性。ResourcesCompat
和 ContextCompat
类中。ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.button_text_csl);在 23+ 版本上直接使用系统的函数,在之前的版本上 AppCompat 自己解析这些 xml 文件从里面提取 attr 属性指代的数值。 AppCompat 同时还支持 ColorStateList 新的
android:alpha
属性。Resources#getDrawable(int)
和前面的两个函数的问题是类似的。 在 Lollipop 之前的版本中无法支持 Theme attr 。VectorDrawableCompat
和 AnimatedVectorDrawableCompat
类中添加了和 AppCompatResources
类类似的功能。比如在 矢量图中你可以使用 ?attr/colorControlNormal
来设置矢量图的颜色,VectorDrawableCompat
会自动完成解析该 属性的工作:<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"> <pathandroid:pathData="..."android:fillColor="@android:color/white"/></vector>小测试
<!-- 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>在应用中定义了如下的 Theme:
<!-- 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>在代码中有如下的函数用来解析颜色值并在代码中创建 ColorStateList:
@ColorIntprivate 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 版本上文字禁用状态和正常状态的颜色,实现代码如下(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);下面是对应的实现截图:
总结
以上就是关于分析Android多主题颜色的相关问题的全部内容,希望本文的内容对大家开发Android能有所帮助。