ContextCompat.getColor() 忽略夜间模式

ContextCompat.getColor() ignore NightMode

TL,DR;

ContextCompat.getColor() 不使用夜间颜色 (values-night/colors.xml),但在启用夜间模式时应该使用。

问题是:

大家好,

所以我正在为我的 Android 应用程序实现一个深色主题,我调用它来启用它: AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

我在 values/colors.xml 中设置了颜色,在 values-night/colors.xml 中设置了深色版本。颜色根据夜间模式变化很好,但是:

当我使用 ContextCompat.getColor(getApplicationContext(), R.id.myColor) 时,它使用正常颜色 (values/colors.xml) 而不是夜间颜色 (values-night/colors.xml)。

在我的 build.gradle 中,我设置了这些:

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0-beta01'

有人可以告诉我我做错了什么吗?

PS : 我已经看过下面的问题,它没有回答这个问题

我在使用夜间模式时遇到了类似的问题。有些屏幕很好,但其他屏幕保持常规主题。最后,我发现我正在使用应用程序的上下文而不是当前的 activity 上下文来实例化一些视图。出于某种原因,应用程序的上下文不会跟踪此类信息。

因此,更新您的代码以使用当前的 activity 上下文而不是应用程序上下文。

供其他用户参考。避免:

ContextCompat.getColor(getApplicationContext(), R.id.myColor)

并使用:

// In a Activity
ContextCompat.getColor(this, R.id.myColor)

// In a View
ContextCompat.getColor(getContext(), R.id.myColor)

// In a Fragment (check against null because getContext can trigger a NPE
Context context = getContext()
if (context != null) {
    ContextCompat.getColor(context, R.id.myColor)
}

我遇到了和你类似的问题,我也发现问题的核心是应用程序没有像Activity这样的主题包装器。所以 W0rmH0le 的回答可以解决这个问题。但对我来说,有很多代码无法获取 activity 或视图的上下文。所以我想我们为什么不创建一个单例上下文包装器 nightMode 主题。 有代码,对我来说很好用。

Resources res = getApplication().getResources();
Configuration configuration = new Configuration(res.getConfiguration());
int nightNode = AppCompatDelegate.getDefaultNightMode();
if (nightNode == AppCompatDelegate.MODE_NIGHT_NO) {
    configuration.uiMode = Configuration.UI_MODE_NIGHT_NO | (res.getConfiguration().uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
} else if (nightNode == AppCompatDelegate.MODE_NIGHT_YES) {
    configuration.uiMode = Configuration.UI_MODE_NIGHT_YES| (res.getConfiguration().uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
} else {
    configuration.uiMode = res.getConfiguration().uiMode;
}
mThemeContext = getApplication().createConfigurationContext(configuration);

然后你可以用mThemeContext替换Application,你就可以在夜间模式下找到合适的颜色。

应用上下文对当前主题或day/night一无所知,因此如果您从应用上下文获取资源,您将在默认应用主题中获取资源。此问题的解决方案是使用 activity/fragment 上下文,但在某些情况下,您可能没有 activity 或片段,只有应用程序上下文。 我创建了一个上下文包装器 class 以将 Day & Night 主题添加到应用程序上下文:

import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat

class ThemedContext(application: Context) {

    private val themedContext: Context

    init {
        val res: Resources = application.resources
        val configuration = Configuration(res.configuration)
        val filter = res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv()

        configuration.uiMode = when (AppCompatDelegate.getDefaultNightMode()) {
            AppCompatDelegate.MODE_NIGHT_NO -> Configuration.UI_MODE_NIGHT_NO or filter
            AppCompatDelegate.MODE_NIGHT_YES -> Configuration.UI_MODE_NIGHT_YES or filter
            else -> res.configuration.uiMode
        }

        themedContext = application.createConfigurationContext(configuration)
    }

    fun getColor(@ColorRes id: Int) = ContextCompat.getColor(themedContext, id)
    fun getDrawable(@DrawableRes id: Int) = ContextCompat.getDrawable(themedContext, id)
    //todo Add other getter methods as needed...
}

此代码已经过测试并有效。