Android - Как определить, включен ли ночной режим при использовании AppCompatDelegate.MODE_NIGHT_AUTO

Я использую встроенные функции Android в режиме день / ночь, и я хотел бы добавить опцию в свое приложение для AppCompatDelegate.MODE_NIGHT_AUTO

У меня проблема, хотя, потому что мое приложение требует, чтобы определенные вещи были окрашены программно, и я не могу понять, как проверить, считает ли приложение себя в ночном или дневном режиме. Без этого я не могу установить флаг, чтобы выбрать правильные цвета.

призвание AppCompatDelegate.getDefaultNightMode() просто возвращает AppCompatDelegate.MODE_NIGHT_AUTO, который бесполезен.

Я не вижу ничего другого, что могло бы сказать мне, но должно быть что-то?

12 ответов

Решение
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;
}

Если вы разработчик котлина, вы можете использовать приведенный ниже код для определения темного режима.

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

Подробнее о режиме темной темы

https://github.com/googlesamples/android-DarkTheme/

Очень простое решение - добавить такой строковый ресурс.

res / values ​​/strings.xml

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

Рез / значения-ночь /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.

чтобы проверить ночной режим, вы можете сделать следующее:

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

Побитовый оператор в Java (который используется в ответе @ephemient) отличается в 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
    }
}

Версия Котлина: ->

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

Начиная с версии 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
            }
    }

Может быть, это просто свойство, которое на самом деле скажет вам, есть ли у вас темный режим?

      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

Для 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
}

Идея использования флага resources.configuration.isNightModeActiveто же самое, что @Carsten. Я бы предложил простую структуру кода.

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
        resources.configuration.isNightModeActive) {

    // code for night mode

} else {

    // code for day mode (or less than API-30)

}

У меня возникли проблемы с тестами пользовательского интерфейса, когда я пытался получить текущую тему в каждом коде ответа. Он каждый раз возвращает одно и то же значение.

Поэтому я создаю статическую переменную в классе приложения и получаю тему для тестов пользовательского интерфейса:

      @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
}

Может быть, кому-то будет полезно!

Я не обнаружил, что это работает после изменения приложения на темную тему с помощью

      AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

Есть ли способ узнать настройки системы после изменения приложения с помощью этого метода?
Спасибо,
FF

Другие вопросы по тегам