Android - 如何在使用AppCompatDelegate.MODE_NIGHT_AUTO时检测夜间模式是否开启

117
我正在使用Android内置的日/夜间模式功能,希望在我的应用程序中添加一个选项来支持AppCompatDelegate.MODE_NIGHT_AUTO。但是,我的应用程序需要以编程方式对某些部分进行着色,而我无法确定如何检查应用程序是否处于夜间或白天模式。如果没有这个信息,我就不能设置一个标记来选择正确的颜色。调用AppCompatDelegate.getDefaultNightMode()只会返回无用的AppCompatDelegate.MODE_NIGHT_AUTO。我没有看到其他任何可以提供信息的内容,但一定有办法吗?

12个回答

181
int nightModeFlags =
    getContext().getResources().getConfiguration().uiMode &
    Configuration.UI_MODE_NIGHT_MASK;
switch (nightModeFlags) {
    case Configuration.UI_MODE_NIGHT_YES:
         doStuff();
         break;

    case Configuration.UI_MODE_NIGHT_NO:
         doStuff();
         break;

    case Configuration.UI_MODE_NIGHT_UNDEFINED:
         doStuff();
         break;
}

谢谢,这解决了问题。我开始尝试检查颜色字符串值以查看它来自哪个资源文件,但这种方法更好! - Ben987654
1
请引用您的来源。https://dev59.com/j1gR5IYBdhLWcg3wZccX - StarWind0
21
@StarWind0 我没有找到其他答案;这个答案纯粹是从API文档中得出的。 - ephemient
@ephemient 所以呢?“请引用您的来源”将API文档链接分享... - Tigerrrrr

55

如果您是 Kotlin 开发人员,则可以使用以下代码来判断暗黑模式。

when (context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK)) {
    Configuration.UI_MODE_NIGHT_YES -> {}
    Configuration.UI_MODE_NIGHT_NO -> {}
    Configuration.UI_MODE_NIGHT_UNDEFINED -> {}
}

了解更多关于暗色主题模式的内容

https://github.com/android/user-interface-samples/tree/main/DarkTheme


6
你的“when”不是穷尽的,针对未定义的情况最好使用“else”。 - Olivier Mercier
好的解决方案,正是我所需要的。 - Belphegor
嗨,现在我们不需要在Kotlin中翻译每个问题的答案,因为IDE会自动进行转换。无论如何,感谢您的努力,尽管遗憾的是它只会增加不必要的滚动条 :( - AndroidEngineX

19

一个非常简单的解决方案是添加一个字符串资源,如下所示。

res/values/strings.xml

<string name="mode">Day</string>

res/values-night/strings.xml

<string name="mode">Night</string>

然后无论您何时需要检查它:

if (resources.getString(R.string.mode) == "Day") {
    // Do Day stuff here
} else {
    // Do night stuff here
}

但是在活动的生命周期中,在super.onCreate()之前您不能调用此方法。在onCreate之前它将始终返回“Day”。


这需要主题是“DayNight”变体吗? - Tim
不,我认为那不应该是一个要求。 - just_user

16

要检查夜间模式,您可以按以下方式操作:

public boolean isNightMode(Context context) {
    int nightModeFlags = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
    return nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
}

13

在 Java 中使用的按位运算符(@ephemient 的答案中使用)与 Kotlin 中不同,因此代码对于初学者来说可能不容易转换。以下是 Kotlin 版本供有需要的人参考:

    private fun isUsingNightModeResources(): Boolean {
        return when (resources.configuration.uiMode and 
Configuration.UI_MODE_NIGHT_MASK) {
            Configuration.UI_MODE_NIGHT_YES -> true
            Configuration.UI_MODE_NIGHT_NO -> false
            Configuration.UI_MODE_NIGHT_UNDEFINED -> false
            else -> false
    }
}

8

Kotlin版本:->

fun isDarkMode(context: Context): Boolean {
    val darkModeFlag = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
    return darkModeFlag == Configuration.UI_MODE_NIGHT_YES
}

3

从Android R(30)开始,context.resources.configuration.isNightModeActive提供了一个值。

所以你不需要再遮盖了。

例如在onConfigurationChanged中:

private var _isNightModeActive: Boolean = false

override fun onConfigurationChanged(newConfig: Configuration) {
        _isNightModeActive =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                _resources.configuration.isNightModeActive
            } else {
                newConfig.uiMode and
                        Configuration.UI_MODE_NIGHT_MASK ==
                        Configuration.UI_MODE_NIGHT_YES
            }
    }

3
也许只是一个属性,可以告诉你是否启用了暗黑模式?
val Context.isDarkMode
    get() = if (getDefaultNightMode() == MODE_NIGHT_FOLLOW_SYSTEM)
        resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
    else getDefaultNightMode() == MODE_NIGHT_YES

1

对于 Xamarin.Android

if (Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
{
    var uiModeFlags = Application.Context.Resources.Configuration.UiMode & UiMode.NightMask;
    switch (uiModeFlags)
    {
        case UiMode.NightYes:
            // dark mode
            break;
        case UiMode.NightNo:
            // default mode
            break;
        default:
            // default mode
            break;
    }
}
else
{
// default mode
}

0

我在UI测试中遇到了问题,每次尝试获取当前主题时都会出现问题。它每次都返回相同的值。

因此,我在应用程序类中创建了静态变量,并通过它获取UI测试的主题:

@Theme
fun Context.getAppTheme(): Int? {
    val theme = when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
        Configuration.UI_MODE_NIGHT_NO -> Theme.LIGHT
        Configuration.UI_MODE_NIGHT_YES -> Theme.DARK
        else -> null
    }

    Application.theme = theme

    return theme
}

在应用程序类中:
companion object {
    @Theme
    @RunNone var theme: Int? = null
}

也许对某些人会有用!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接