当前位置: 移动技术网 > IT编程>移动开发>Android > 分析Android多主题颜色的相关问题

分析Android多主题颜色的相关问题

2019年07月24日  | 移动技术网IT编程  | 我要评论

北京舞蹈学院邢睿,长春花图片,国语动画

如果您通过以下的代码来获取定义的颜色值

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) & resources#getcolorstatelist(int) 的问题

首先来看看这两个被废弃的函数是干啥的:
      – resources#getcolor(int) 返回一个资源 id 对应的颜色值,如果该资源为 colorstatelist 则返回 colorstatelist 的默认颜色值

      – resources#getcolorstatelist(int) 返回对应的 colorstatelist

上面的代码在什么情况下会破坏我的代码呢?

要理解为何废弃这两个函数,来看个 colorstatelist 的例子。 当在 textview 中使用自定义的 colorstatelist 的时候, textview 不可用状态和可用状态的文字颜色分别使用 r.attr.coloraccentr.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>

现在如果您通过如下的代码来获取这个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 属性。

在新版本的 support 库中也有对应的实现,分别位于 resourcescompat contextcompat 类中。

如何解决该问题呢?

使用 appcompat v24+ 版本可以很容易的解决该问题。

colorstatelist csl = appcompatresources.getcolorstatelist(context, r.color.button_text_csl);

在 23+ 版本上直接使用系统的函数,在之前的版本上 appcompat 自己解析这些 xml 文件从里面提取 attr 属性指代的数值。 appcompat 同时还支持 colorstatelist 新的 android:alpha 属性。

resources#getdrawable(int) 的问题

resources#getdrawable(int) 和前面的两个函数的问题是类似的。 在 lollipop 之前的版本中无法支持 theme attr 。

为啥我这样用也没有出现异常呢?

异常并不总是会出现。

vectordrawablecompatanimatedvectordrawablecompat 类中添加了和 appcompatresources 类类似的功能。比如在 矢量图中你可以使用 ?attr/colorcontrolnormal 来设置矢量图的颜色,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>

小测试

下面使用一个小测试来回顾一下前面介绍的内容。 假设有下面一个 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>

在应用中定义了如下的 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>

在代码中有如下的函数用来解析颜色值并在代码中创建 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 版本上文字禁用状态和正常状态的颜色,实现代码如下(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能有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网