Урок в Android Studio: разработка на Kotlin — тёмная тема

Современный пользователь ожидает, что приложение будет комфортным для глаз в любое время суток. Разработка на Kotlin в Android Studio учитывает это. Грамотная разработка обязана это учитывать. Настройка тем через ресурсы — важный аспект Android разработки. Переключение между светлым и тёмным оформлением в Android Studio. Днём тёмный интерфейс может плохо читаться, поэтому важна гибкая разработка на Kotlin. В приложении нужно предусмотреть возможность выбора режима. Kotlin позволяет реализовать такие функции.


Как устроены темы в Android

Оформление приложения описывается в папке res/values в файле themes.xml. Он наследуется от одной из базовых тем, например Theme.MaterialComponents.DayNight.NoActionBar. Приставка DayNight означает, что система автоматически выбирает светлую или тёмную версию в зависимости от настроек устройства. Но чтобы это работало, нужно подготовить два набора ресурсов: для светлого режима и для ночного.

Цвета обычно хранятся отдельно — в файле colors.xml. Чтобы автоматически переключать их, создают второй файл colors.xml в папке res/values-night. Тогда при включении ночного режима система подставит значения из этой папки.


Создание ночного набора ресурсов

Щёлкните правой кнопкой по папке res и выберите New → Android Resource Directory. В поле Resource type укажите values, а в поле Directory name введите values-night. Android Studio создаст новую папку. Скопируйте в неё файл colors.xml и замените значения на тёмные оттенки.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="background">#121212</color>
    <color name="surface">#1E1E1E</color>
    <color name="text_primary">#FFFFFF</color>
    <color name="text_secondary">#B0B0B0</color>
</resources>

В основной папке values оставьте светлые значения с теми же именами. Теперь при переключении режима цвета будут меняться сами, без правок в коде.


Настройка темы в themes.xml

В файле themes.xml проверьте, что ваша тема наследуется от DayNight-варианта. Если да, достаточно указать, какие цвета использовать для фона и текста.

<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="android:windowBackground">@color/background</item>
    <item name="android:textColorPrimary">@color/text_primary</item>
    <item name="android:textColorSecondary">@color/text_secondary</item>
    <item name="colorPrimary">@color/purple_500</item>
</style>

После сборки приложение автоматически подхватит нужный набор цветов при смене системной темы.


Программное переключение режима

Иногда пользователю нужно вручную выбрать оформление, независимо от системных настроек. Для этого используется AppCompatDelegate. Метод setDefaultNightMode принимает одну из констант: MODE_NIGHT_YES (тёмная), MODE_NIGHT_NO (светлая) или MODE_NIGHT_FOLLOW_SYSTEM (как в системе).

btnDarkTheme.setOnClickListener {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    recreate() // пересоздаём Activity для применения
}

btnLightTheme.setOnClickListener {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
    recreate()
}

btnSystemTheme.setOnClickListener {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
    recreate()
}

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


Сохранение выбора пользователя

Чтобы приложение запоминало выбранный режим, сохраните его в DataStore или SharedPreferences. При запуске считывайте значение и сразу устанавливайте нужный режим в onCreate до вызова setContentView.

override fun onCreate(savedInstanceState: Bundle?) {
    val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
    val mode = prefs.getInt("night_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
    AppCompatDelegate.setDefaultNightMode(mode)

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

Теперь при повторном запуске приложение откроется в выбранном ранее оформлении.


Особенности Jetpack Compose

Если вы пишете интерфейс на Compose, подход немного отличается. Там цвета берутся из MaterialTheme.colorScheme, а тема строится функцией MyAppTheme. Внутри неё проверяется системная настройка через isSystemInDarkTheme(), и выбирается соответствующий набор цветов. Для ручного переключения используется то же решение — AppCompatDelegate.

@Composable
fun MyAppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val colors = if (darkTheme) DarkColorScheme else LightColorScheme
    MaterialTheme(colorScheme = colors, content = content)
}

Полезные мелочи

  • Проверяйте контрастность. Убедитесь, что текст читается на тёмном фоне. Не используйте чистый чёрный — он даёт слишком резкий контраст. Значение #121212 считается оптимальным.
  • Тестируйте на разных устройствах. Некоторые производители добавляют свои переключатели тем, которые могут конфликтовать с вашей логикой.
  • Не забывайте про изображения. Если у вас есть тёмные иконки, подготовьте их светлые версии для ночного режима и храните в папке drawable-night.

Что мы освоили

Сегодняшний материал показал, как добавить в приложение поддержку светлого и тёмного оформления. Вы научились создавать набор ресурсов для ночного режима, настраивать тему через themes.xml и управлять переключением из кода. Эти навыки — важная часть профессиональной android разработки на kotlin, ведь качественный интерфейс учитывает предпочтения пользователя. Теперь ваше приложение будет комфортным для глаз в любое время суток. Попробуйте добавить экран выбора темы в настройки — это займёт пару минут и сделает интерфейс ещё дружелюбнее.