DayNight: настраиваем автоматическую смену темы в android в зависимости от времени суток

О том, как настроить DayNight тему в приложении андроид, которая устанавливает темную или светлую тему оформления вашего приложения на основе времени суток и текущего местоположения

Мы уже писали, что вышла новая библиотека поддержки Android Support Library 23.2. Новая либа добавляет сразу несколько интересных вещей: это и поддержка векторных изображений в android ниже 5.0, и новые элементы материального дизайна, такие как Bottom Sheets.

Одна из фишек – новая тема DayNight с поддержкой автоматического переключения между светлой и темной темой оформления в зависимости от времени суток. Ее то мы сегодня и потестируем.

Об этом смотрите видео, а под видео – подробнее от разработчиков том, как гибко можно настроить работу и ресурсы для темы DayNight.

Theme.AppCompat.DayNight –  это переключение между Theme.AppCompat (темной) и Theme.AppCompat.Light (светлой) на основе времени суток. Это имеет много преимуществ для пользователей, особенно если у вас content app . Эта функция работает на API v14 и выше, на младших версиях будет по умолчанию светлая тема.

Как использовать Theme.AppCompat.DayNight ?

Просто унаследуйте вашу тему от одного из вариантов DayNight в файле res/values/styles.xml:

<style name="MyTheme" parent="Theme.AppCompat.DayNight">
    <!-- ... -->
</style>

Затем необходимо включить функцию в вашем приложении. Сделайте это путем вызова статического метода AppCompatDelegate.setDefaultNightMode(), который принимает одно из четырех значений:

  • MODE_NIGHT_NO. Всегда используется дневная тема (светлая).
  • MODE_NIGHT_YES. Всегда используется ночная тема (темная).
  • MODE_NIGHT_AUTO. Автоматическое изменение между светлой/темной, в зависимости от времени суток.
  • MODE_NIGHT_FOLLOW_SYSTEM (по умолчанию). Это системный параметр, который является по существу MODE_NIGHT_NO на момент написания (подробнее об этом ниже).

Вызов метода static, поэтому его можно вызвать в любое время. Устанавливаемое значение не сохраняется,  поэтому вам нужно установить его каждый раз, когда ваше приложение стартует. Рекомендуется устанавливать его в статический блок в классе вашего приложения (если у вас он один), или вашей Activity, так:

static {
    AppCompatDelegate.setDefaultNightMode(
            AppCompatDelegate.MODE_NIGHT_...);
}

Метод setLocalNightMode()

Можно переопределить значение по умолчанию в каждом компоненте путем вызова его AppCompatDelegate setLocalNightMode(). Это удобно, когда вы знаете, что только некоторые компоненты должны использовать функцию DayNight, или для тестирования, чтобы не сидеть и ждать ночи для проверки макета.

Обратите внимание, что этот вызов не заботится о восстановлении,  если изменить режим ночь после любого вызова inflate(), он не будет иметь никакого эффекта. В этом случае можно использовать вызов recreate():

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            // Set the local night mode to some value
            getDelegate().setLocalNightMode(
                    AppCompatDelegate.MODE_NIGHT_...);
            // Now recreate for it to take effect
            recreate();
        }
    }
}

Как проверить, какой режим может использовать мое приложение?

Просто проверьте конфигурацию ресурсов:

int currentNightMode = getResources().getConfiguration().uiMode
        & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
    case Configuration.UI_MODE_NIGHT_NO:
        // Night mode is not active, we're in day time
    case Configuration.UI_MODE_NIGHT_YES:
        // Night mode is active, we're at night!
    case Configuration.UI_MODE_NIGHT_UNDEFINED:
        // We don't know what mode we're in, assume notnight
}

Если приложение выглядит странно

Например, текст нечитабельный или иконки неправильного цвета.

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

Возьмите за правило для этих вещей всегда использовать атрибуты темы, по возможности. Вот наиболее важные:

  • ?android:attr/textColorPrimary – Цвет текста общего назначения. Будет черным для светлой темы, и белым для темной темы.
  • ?attr/colorControlNormal – Цвет значка общего назначения.

WebView

Существует один большой нюанс этой функции: WebViews. Поскольку они не могут использовать атрибуты темы, и вы редко имеете контроль над любым веб-контентом, существует высокая вероятность того, что ваш WebView будет слишком контрастным против динамического оформления приложения. Поэтому проверьте ваше приложение в обоих режимах, чтобы убедиться что оформление не будет раздражать пользователя.

Местоположение

Чтобы иметь возможность рассчитать корректное переключение между днем или ночью, нам нужно знать ваше местоположение.  Если ваше приложение уже имеет разрешения для определения местоположения, AppCompat будет попытаться захватить последнее известное местоположение от LocationManager и использовать их для вычисления времени восхода и захода солнца. Однако он не будет просить разрешения от вашего имени.
Если вы не установили эти разрешения (или просто нет последнего известного местоположения), в настоящее время используются некоторые фиксированные значения. Например это 6 утра (начало дня) и 10 вечера (начало ночи), но это может измениться в будущем, по словам разработчиков.
Если вы ориентируетесь на Android SDK версии 23, вы будете использовать разрешения времени выполнения. Можно реализовать в вашем приложении настройку, позволяя пользователю выбрать включение функциональности DayNight. Это хороший способ, чтобы запрашивать разрешения определения местоположения, если требуется высокая точность определения времени восхода/заката.

Почему просто не сделать AUTO по умолчанию?

Существует несколько причин, которые станут понятны после просмотра примерного сценария для использования этого:

  1. Изменить тему продления от Theme.AppCompat.DayNight.
  2. Добавить установку в вашем приложении, предоставив пользователю выбор. На этом этапе сохранить настройки (вероятно, в SharedPreference). Вызов setDefaultNightMode () с выбранным значением.

Тогда в следующий раз, когда ваше приложение запускается, прочитать сохраненное значение и вызвать setDefaultNightMode () снова с выбранным значением.

Таким образом, основная причина заключается в том , не желательно, чтобы ваш пользователь обновил приложение, и вдруг обнаружил , что оно меняет цвет случайным образом (для него) на основе времени суток. Кроме того, по умолчанию MODE_NIGHT_FOLLOW_SYSTEM, поэтому если разработчики добавят user-visible setting  на платформу в будущем, AppCompat будет автоматически использовать его.

Можно ли использовать свои собственные ресурсы для темы день / ночь?

Да, можно. AppCompat в простых терминах просто позволяет использовать отдельные ресурсы ночного режима в любое время. Они на самом деле были доступны в платформе, начиная с API 8, но использовались только в очень конкретном сценарии: в режиме автомобиля и стыковки.

Так что под капотом Theme.AppCompat.DayNight просто реализован в таком виде:

res/values/themes.xml

<style name="Theme.AppCompat.DayNight" 
       parent="Theme.AppCompat.Light" />

res/values-night/themes.xml

<style name="Theme.AppCompat.DayNight" 
       parent="Theme.AppCompat" />

Это означает, что вы можете также добавить ваши ресурсы для дневного и ночного времени. Просто используйте –night квалификатор для вашей папки ресурсов: drawable-night, values-night, и т.д.

Источники:

AppCompat v23.2 — DayNight
Android Support Library 23.2

Коментарі: 2
  1. Максим

    У меня в приложении по собственному стилю цвет текста (заголовка) в action bar был белый, но после установки на DayNight стал чёрным, и никакие стили и темы никак не влияют, чтобы обратно сделать белым, как это решить?

Додати коментар