`context.getColor`中`theme`有什么用?

and*_*per 3 android android-theme android-resources

背景

从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

问题

文档对的内容不多说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);
Run Code Online (Sandbox Code Playgroud)

这有点奇怪,因为在幕后,似乎并没有对主题做任何事情。这是它的代码:

@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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

查看Context.getColor,我可以看到:

在此处输入图片说明

在我看来,它使用的是活动的主题?

问题

  1. “主题”参数的目的是什么?

  2. 如何使用?是否有关于它的任何样本/教程/文章?

  3. 为什么仍然不推荐使用该功能?对我来说仍然可以安全使用...

  4. 支持库功能有什么用?与不赞成使用的功能有何不同?

Eug*_*nec 10

tl; dr

  • 如果您的最小SDK为23,则不需要compat API来获取颜色。
  • 如果您不使用主题主题颜色引用并且不计划更改,请使用Context.getResources().getColor(int)getColorStateList(int)习惯使用。已将其标记为已弃用,但从功能上来说还可以。
  • 如果您只想在API 23+上的颜色中使用主题属性引用,请使用ContextCompat.getColorStateList(Context, int)
  • 如果您使用AppCompat并希望能够在所有版本的Android上使用主题属性引用,请使用AppCompatResources.getColorStateList(Context, int)

从API 23开始,ColorStateList可以包含主题属性引用,这是Drawable自API 21以来允许的。

主题属性主要用于通过getColorStateList方法获得的颜色状态列表中,getColor因此从现在开始我将使用它。提到的大多数内容都适用于这两种变体。

例:

分辨率/颜色/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>
Run Code Online (Sandbox Code Playgroud)

“主题”参数的目的是什么?

解析主题属性需要主题。资源本身不知道任何主题。主题由上下文提供。

context.getColorStateList(R.color.my_csl);
Run Code Online (Sandbox Code Playgroud)

本质上是

context.getResources().getColorStateList(R.color.my_csl, context.getTheme());
Run Code Online (Sandbox Code Playgroud)

这两种方法都是公共API的一部分,因此它们都被反向移植:

ContextCompat.getColorStateList(context, R.color.my_csl);
ResourcesCompat.getColorStateList(context.getResources(), R.color.my_csl, context.getTheme());
Run Code Online (Sandbox Code Playgroud)

如何使用?

通常情况如下:

final int myColor = ContextCompat.getColorStateList(context, R.color.my_csl);
Run Code Online (Sandbox Code Playgroud)

如果您使用AppCompat,则最好使用另一种选择:

final int myColor = AppCompatResources.getColorStateList(context, R.color.my_csl);
Run Code Online (Sandbox Code Playgroud)

这是这两个选项之间的比较:

  • ContextCompat.getColorStateList

    • 只需要support-compat支持库
    • 仅回传API-尝试解析API 23以下的主题属性时将崩溃
  • AppCompatResources.getColorStateList

    • 需要完整的appcompat-v7支持库
    • 反向功能-即使在API 23以下,它也将尊重上下文主题

ResourcesCompat.getColorStateList(int, Theme)是API(非功能性)的反向端口,Resources.getColorStateList(int, Theme)Context.getColorStateList(int)API 23+ 内部使用。在日常使用中,您将不需要此方法。

为什么仍然不推荐使用该功能?对我来说仍然可以安全使用...

不建议使用该方法,以将开发人员从不了解主题的版本迁移到该方法的主题感知版本。

只要您使用主题感知方法来获取没有主题属性引用的颜色,该方法仍然非常安全,例如:

res / values / colors.xml

<resources>
    <color name="my_cint">#f00</color>
</resources>
Run Code Online (Sandbox Code Playgroud)

可以通过安全地获得

context.getResources().getColor(R.color.my_cint);
Run Code Online (Sandbox Code Playgroud)

支持库功能有什么用?

ContextCompat.getColorStateList(context, R.color.my_csl);
Run Code Online (Sandbox Code Playgroud)

从字面上是这个

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

该方法存在,因此您不必在所有地方都编写if-else。而已。

在API 23+上,它可以使用上下文主题。在API 23以下,它会退回到无法解析主题属性的旧版本。

ResourcesCompat.getColorStateList(int, Theme) 外观和工作方式类似,它会忽略API 23下的主题属性(使用它们时出现崩溃)。

AppCompatResources.getColorStateList(Context, int) 不会崩溃,并且不能在所有版本的Android上正确解析主题属性。

ResourcesCompat#getColorStateList

您通常不需要此方法。

这是抽象层。它告诉你,要解决一个颜色,你不需要任何神的对象,任何ContextResources足以解决颜色。但是为了Resources能够解析主题属性,您需要提供ThemeTheme可以从a获得a 的事实Context与无关ResourcesResources我不会透露或关心它本身是来自某些人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。如上所述,它们的实际用途值得商bat。

我建议阅读下面的讨论,以掌握一些难以捉摸的细微差别。