从API 23开始,不推荐使用获取资源的getColor(通过给它资源ID)的小方法:
相反,我们被告知使用包含Theme
参数的方法:
此方法在API级别23中已弃用。请改用getColor(int,Theme)。
https://developer.android.com/reference/android/content/res/Resources.html#getColor(int,android.content.res.Resources.Theme)
The docs对theme
说不多:
https://developer.android.com/reference/android/content/res/Resources.html#getColor(int,android.content.res.Resources.Theme)
通过Internet搜索,我能找到的是我们可以使用支持库来获取颜色:
ContextCompat.getColor(context, R.color.color_name);
这有点奇怪,因为在幕后,看起来它似乎没有做任何主题。这是它的代码:
@ColorInt
public static final int getColor(@NonNull Context context, @ColorRes int id) {
if (Build.VERSION.SDK_INT >= 23) {
return context.getColor(id);
} else {
return context.getResources().getColor(id);
}
}
看看Context.getColor,我可以看到:
所以在我看来它正在使用活动的主题?
tl;博士
Context.getResources().getColor(int)
或getColorStateList(int)
。它被标记为已弃用,但在功能上它没关系。ContextCompat.getColorStateList(Context, int)
。AppCompatResources.getColorStateList(Context, int)
。启动API 23 ColorStateList
可以包含主题属性引用,这与API 21以来在Drawable
中允许的相同。
主题属性主要用于通过getColorStateList
方法获得的颜色状态列表,而不是getColor
,所以我将从现在开始使用它。所提到的大部分内容适用于这两种变体。
例:
RES /颜色/ my_csl.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="?attr/colorControlHighlight" android:alpha="?android:disabledAlpha"/>
<item android:color="?attr/colorControlHighlight"/>
</selector>
“主题”参数的目的是什么?
主题是解析主题属性所必需的。资源本身并不知道任何主题。主题由上下文提供。
context.getColorStateList(R.color.my_csl);
本质上是一个快捷方式
context.getResources().getColorStateList(R.color.my_csl, context.getTheme());
这两种方法都是公共API的一部分,因此它们都被反向移植:
ContextCompat.getColorStateList(context, R.color.my_csl);
ResourcesCompat.getColorStateList(context.getResources(), R.color.my_csl, context.getTheme());
怎么用?
通常它就像这样简单:
final int myColor = ContextCompat.getColorStateList(context, R.color.my_csl);
如果您使用AppCompat,您可能会选择其他选项:
final int myColor = AppCompatResources.getColorStateList(context, R.color.my_csl);
以下是这两个选项之间的比较:
ContextCompat.getColorStateList
仅需要support-compat
支持库
仅向后移植API - 尝试解析API 23下的主题属性时会崩溃AppCompatResources.getColorStateList
需要完整的appcompat-v7
支持库
Backports功能 - 即使在API 23下也会尊重上下文主题ResourcesCompat.getColorStateList(int, Theme)
是Resources.getColorStateList(int, Theme)
的API(非功能性)后端,Context.getColorStateList(int)
在API 23+上内部使用。在日常使用中,您将不需要这种方法。
为什么函数不赞成?它对我来说似乎仍然安全......
不推荐使用该方法将开发人员从不知道主题的版本迁移到方法的主题感知版本。
只要你使用它来获取没有主题属性引用的颜色,主题不知道的方法仍然是完全安全的,例如:
RES /值/ colors.xml
<resources>
<color name="my_cint">#f00</color>
</resources>
可以安全地获得
context.getResources().getColor(R.color.my_cint);
支持库函数有什么用?
ContextCompat.getColorStateList(context, R.color.my_csl);
字面意思是这个
public static final ColorStateList getColorStateList(Context context, @ColorRes int id) {
if (Build.VERSION.SDK_INT >= 23) {
return context.getColorStateList(id);
} else {
return context.getResources().getColorStateList(id);
}
}
该方法存在,因此您不必在任何地方编写if-else。而已。
在API 23+上,它可以使用上下文主题。在API 23下面,它回退到无法解析主题属性的旧版本。
ResourcesCompat.getColorStateList(int, Theme)
看起来和工作方式类似,它忽略了API 23下面的主题属性(当你使用它们时崩溃)。
AppCompatResources.getColorStateList(Context, int)
不会崩溃并正确解析所有Android版本的主题属性。
怎么样
ResourcesCompat#getColorStateList
?
您通常不需要此方法。
这是一个抽象层。它告诉你,要解决一种颜色,你不需要任何神对象,任何Context
。 Resources
足以解决一种颜色问题。但是Resources
能够解决你需要提供Theme
的主题属性。可以从Theme
获得Context
的事实与Resources
无关。 Resources
没有透露或关心它本身来自一些Context.getResources()
。
你能[...]更新
getColor
吗?
getColor
将解决
<color>
资源为颜色整数<selector>
颜色状态列表资源作为其默认颜色的颜色整数getColorStateList
将解决
<color>
资源为ColorStateList
有一种颜色<selector>
CSL资源为具有指定颜色的ColorStateList
使用消费者API所需的那个。
没有AppCompatResources.getColor(Context, int)
,因为颜色资源被定义为主题属性引用几乎没有意义。如果你需要这个AppCompatResources.getColorStateList(Context, int).getDefaultColor()
是功能相当的。
ContextCompat.getColor(Context, int)
和ResourcesCompat.getColor(Resources, int, Theme)
存在是因为它们反映了框架API。如上所述,它们的实用性是值得商榷的。
我建议阅读下面的讨论,以掌握一些难以捉摸的微妙差异。