- DayNight — Adding a dark theme to your app
- How do I use it?
- setDefaultNightMode
- setLocalNightMode
- Activity recreations
- How can I check what configuration I’m currently in?
- WebViews
- System night mode
- In-app setting
- Updating your themes + styles
- Using your own resources for dark/light
- Why should I move to using setDefaultNightMode?
- How to implement a dark theme on Android
- 1. Declare dependencies
- 2. Inherit from a DayNight theme
- 3. Use theme attributes for colors
- 4. Allow users to change the app’s theme
- 5. Run your app
- Sample
- How do I force apply a dark theme on Android Studio?
- 2 Answers 2
- Как реализовать тёмную тему в Android-приложении?
- Теперь давайте начнём
- Переходим к коду
- Проверка текущей темы системы
- Ещё немного настроек
DayNight — Adding a dark theme to your app
This post has been updated multiple time since first publishing. The content is correct as-of April 26th 2019.
The DayNight functionality in AppCompat allows your app to easily switch between a dark ⚫ and light ⚪ theme. This has many benefits for your users, from saving power on OLED displays, to increasing usability for people with reduced-vision, and more.
How do I use it?
You need to change your theme to extend from one of the DayNight variants, and then call one method to enable the feature. Here’s an example theme declaration:
If you’re using Material Design Components (and I recommend you to do so), then you can also use the Theme.MaterialComponents.DayNight theme from their v1.1.0 release. The rest of this post remains the same.
You then need to enable the feature in your app using one of the APIs provided.
setDefaultNightMode
The first API we provide to do that is AppCompatDelegate.setDefaultNightMode() , which takes one of the follow values:
- MODE_NIGHT_NO . Always use the day (light) theme.
- MODE_NIGHT_YES . Always use the night (dark) theme.
- MODE_NIGHT_FOLLOW_SYSTEM (default). This setting follows the system’s setting, which on Android Q and above is a system setting (more on this below).
- MODE_NIGHT_AUTO_BATTERY . Changes to dark when the device has its ‘Battery Saver’ feature enabled, light otherwise.
✨ New in v1.1.0-alpha03. - MODE_NIGHT_AUTO_TIME & MODE_NIGHT_AUTO . Changes between day/night based on the time of day.
⛔ Deprecated in v1.1.0-alpha03.
The method is static so you can call it at any time. The value you set is not persisted across process starts though, therefore you need to set it every time your app process is started. I recommend setting it in your application class (if you have one) like so:
From AppCompat v1.1.0-alpha05 onwards, setDefaultNightMode() will automatically apply any DayNight changes to any ‘started’ Activities. This means that you no longer have to manually recreate any Activities when you call the API.
setLocalNightMode
You can also override the default value in each component with a call to its AppCompatDelegate’s setLocalNightMode() . This is handy when you know that only some components should use the DayNight functionality, or for development so that you don’t have to sit and wait for night to fall to test your layout.
Using this method in every Activity is now an anti-pattern, and you should move to using setDefaultNightMode() instead. See the section below for the technical details to why.
Activity recreations
Both of the methods mentioned above will recreate your Activity if a Configuration change is required, so that the new theme can be applied. This is a good opportunity to test whether your Activity + Fragments save their instance state correctly.
How can I check what configuration I’m currently in?
You can do this by checking your resource configuration:
WebViews
There is currently one big caveat to using this feature: WebViews. Since they can not use theme attributes, and you rarely have control over any web content’s styling, there is a high probability that your WebViews will be too contrasting against your dynamic themed app. So make sure you test your app in both modes to ensure that it’s not annoying to the user.
System night mode
Android Q onwards has a system night mode which can be enabled in the Settings app. Android Pie also has a system night mode setting, but it is only surfaced in the device’s ‘developer options’. For ease, I recommend treating Android Pie the same as previous versions of Android.
In-app setting
It is recommended to provide a way for the user to override the default theme in your app. The recommended options and strings are:
- ‘Light’ ( MODE_NIGHT_NO )
- ‘Dark’ ( MODE_NIGHT_YES )
- ‘Set by Battery Saver’ ( MODE_NIGHT_AUTO_BATTERY ).
Only show on Android Pie and below. This should be your app’s default when shown. - ‘Use system default’ ( MODE_NIGHT_FOLLOW_SYSTEM ).
Only show on Android Q and above. This should be your app’s default when shown.
A common way to do to implement would be via a ListPreference, calling to setDefaultNightMode() when the value changes.
Updating your themes + styles
As well as calling AppCompat, you will likely need to do some work to update your themes, styles and layouts so that they work seamlessly across both dark and light themes.
The rule-of-thumb for these things is to always use theme attributes when you can. Here are the most important to know about:
- ?android:attr/textColorPrimary . General purpose text color. Will be near-black on light theme, near-white on dark themes. Contains a disabled state.
- ?attr/colorControlNormal . General-purpose icon color. Contains a disabled state.
Using Material Design Components also makes this a lot easier, as it’s attributes (such as ?attr/colorSurface and ?attr/colorOnSurface ) provide you an easy generalized themed color to use. These attributes of course can be customized in your theme.
Using your own resources for dark/light
AppCompat in simple terms is just enabling the use of the night and notnight resource qualifiers. These have actually been available in the platform since API 8, but were previously only used in very specific scenarios.
Under the hood Theme.AppCompat.DayNight is implemented as so:
This means that you can also provide alternative resources for your light and dark UIs. Just use the — night qualifier on your resource folders: drawable-night , values-night , etc.
Why should I move to using setDefaultNightMode?
In AppCompat v1.1.0, DayNight had a big rewrite in order to fix a number of bugs. The biggest bug was this:
- WebView would reset the Activity configuration as soon as it was loaded into the process. This could lead to later inflated views using the wrong theme.
AppCompat needs to change the Activity’s resources configuration to enable “night mode”. The problems with WebView stemmed from using a now deprecated method: Resources.updateConfiguration() to achieve that. Unfortunately WebView doesn’t work very well with that method (hence the deprecation).
The rewrite focused on moving to a newer method to update the configuration: ContextThemeWrapper.applyOverrideConfiguration() . Unfortunately, that API is a lot more tricky to use since it can only be called before any call to getResources() . It turns out getResources() is called a lot, and gets called very early on in the Activity lifecycle. In fact the only place I found where it could be called safely is in attachBaseContext() , which is a lot earlier than onCreate() .
OK, I’ve just told you a lot of technical stuff about the internals of DayNight, so what does that have to do with setDefaultNightMode() ? Well because we can only call applyOverrideConfiguration() in attachBaseContext() , this gives us a very small window for setLocalNightMode() to work without having to recreate the Activity.
Previously you could do the following quite happily, without AppCompat needing to recreate the Activity:
Due to what we’ve spoken about above, that will now trigger a recreation in the new version of DayNight. In fact, any call to setLocalNightMode will trigger a recreation (if the theme changes).
This is the crux of why you should now prefer setDefaultNightMode() , to minimize unnecessary recreations. Since it’s a static method, the value is always available, and isn’t beholden to the Activity lifecycle. The method models what most apps want to do anyway, which is provide an app-wide setting or preference.
That doesn’t mean that setLocalNightMode is wrong to use, just use it for what it is meant for: one-off overrides in individual Activities.
Источник
How to implement a dark theme on Android
Android 10 adds a system-wide dark theme, which preserves battery power for devices with OLED screens, reduces eye strain, and facilitates use in low-light environments.
These guidelines will show you how to implement a dark theme on Android, even on earlier versions of the platform.
1. Declare dependencies
Add the following dependencies to your project:
2. Inherit from a DayNight theme
The easiest way to support a dark theme is to inherit from a DayNight theme such as Theme.AppCompat.DayNight .
Basically, a DayNight theme is composed of a Light theme in the values directory and a Dark theme in the values-night directory.
For example, declare a Theme.MaterialComponents.DayNight.NoActionBar.Bridge :
And then, declare your AppTheme :
3. Use theme attributes for colors
When writing your layouts, use theme attributes or night-qualified resources instead of hard-coded colors to ensure that they display suitable colors in a Light theme and in a Dark theme.
For example, when you use a FloatingActionButton , the default backgroundTint is ?attr/colorAccent so the tint should be ?android:attr/textColorPrimaryInverse to ensure that the contrast ratio between the icon and its background is eligible:
In a Light theme, it will display a #ffffffff icon on a #ff009688 background.
In a Dark theme, it will display a #de000000 icon on a #ff80cbc4 background.
4. Allow users to change the app’s theme
Your app should let the user switch between themes, which map directly to one of the following modes:
Use AppCompatDelegate.setDefaultNightMode to switch the theme for all components in your app. Please note that it is not saved when the app is killed so you should use Settings to save the user’s choice.
For example, use the following code in your Activity to change the night mode:
And then, use the following code in your Application to restore the night mode:
5. Run your app
That’s it, you are ready to run your app and enjoy a dark theme!
Sample
For a complete example, check out my sample on GitHub.
Источник
How do I force apply a dark theme on Android Studio?
According to the docs, I only need to set android:forceDarkAllowed=true in my activity manifest and inherit theme from parent=»Theme.MaterialComponents.DayNight» . I tried that, but it didn’t work.
Here’s my manifest file:
And here’s my styles.xml styles:
I tried to get the theme name of the activity by using this code below:
It shows me com.example.name:style/AppTheme and not AppTheme.Dark . How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed ?
2 Answers 2
That is not how dark mode works on Android 10.
First, Android does not magically append .Dark to your theme at any point, regardless of whether or not the user enabled dark mode. You have android:theme=»@style/AppTheme» . So, Android will use AppTheme all the time, and your AppTheme.Dark will not be used.
Second, the idea behind DayNight is that you use that as you base theme all the time, and Android will switch between normal and dark modes based on user request. So, if you switch AppTheme to extend DayNight , and get rid of AppTheme.Dark , you will be matching what the documentation calls for.
android:forceDarkAllowed is for cases where you are not in position to use a DayNight theme, and you want Android to try to automatically convert your UI to a dark theme. If you wanted to keep AppTheme extending Light instead of DayNight , this might work (I personally have not tried it with a MaterialComponents theme). But, even then, it will only be when the user has enabled dark mode (e.g., tapped on the notification shade tile).
For example, in this sample app, I use DayNight for my theme:
I have different definitions for those colors in res/values/ and res/values-night/ . I do not use forceDarkAllowed . And, when the user toggles night mode, my UI goes from:
How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed?
If you want a dark theme all the time, use a regular theme (not Light , not DayNight ).
Источник
Как реализовать тёмную тему в Android-приложении?
С тех пор, как в Android Pie (9.0) появилась тёмная тема, многие популярные приложения с радостью начали использовать эту функцию. И мы тоже. Учитывая, что нам нравится пробовать новые вещи, мы решили попробовать и внедрить эту функцию в одно из наших приложений.
Я максимально просто опишу процесс реализации тёмной темы приложения с использованием библиотеки AppCompat из AndroidX.
Прежде чем мы начнём, вот вам совет: если вы работаете над какими-либо новыми проектами, то настоятельно рекомендуется использовать библиотеки из AndroidX. Кроме того, вам следует рассмотреть возможность переноса существующих проектов на AndroidX.
Теперь давайте начнём
Сначала импортируйте последнюю версию AppCompat из AndroidX:
В этой версии AppCompat будут все новые обновления и исправленные ошибки, связанные с тёмной темой.
Затем измените тему своего приложения на Theme.AppCompat.DayNight :
Переходим к коду
Измените текущую тему во время запуска приложения (рекомендуется делать это в классе Application приложения). Начиная с версии 1.1.0-aplha05 этот метод будет применять эти изменения к любой запущенной activity. Изменения также будут сохраняться при всех изменениях конфигурации, поэтому не нужно вызывать метод recreate() .
Вот четыре режима, которые мы используем в нашем приложении для выбора темы:
- MODE_NIGHT_NO — устанавливает светлую тему.
- MODE_NIGHT_YES — устанавливает тёмную тему.
- MODE_NIGHT_AUTO_BATTERY — переключается на тёмную тему, если на устройстве включена функция экономии заряда батареи. Этот режим доступен с версии 1.1.0-alpha03 .
- MODE_NIGHT_FOLLOW_SYSTEM — использует системную тему.
- MODE_NIGHT_AUTO_TIME и MODE_NIGHT_AUTO — устанавливает тему в зависимости от времени устройства. Этот режим устарел с версии 1.1.0-alpha03 , поэтому мы не используем его в нашем приложении.
Внутри приложения есть RadioGroup для переключения между различными темами:
Вот как это выглядит на устройстве:
Не забывайте, что функциональность тёмной темы поддерживается только с версии Android Pie (9.0), поэтому вам нужно предусмотреть поведение для предыдущих версий Android:
Проверка текущей темы системы
Фрагмент из нашего приложения:
Обратите внимание, что конфигурация возвращается только при наличии ночной или дневной темы (или если вообще ничего не определено), но мы не знаем, установлена ли она системой, батареей или вручную. Поэтому мы используем shared preferences, чтобы сохранить выбранную тему и установить соответствующий флажок. Вот полный код:
Когда приложение запускается в первый раз, в shared preferences будет неопределённое состояние. В этом случае мы проверим, есть ли у нас тема из конфигурации. Если нет, мы будем использовать светлую тему по умолчанию.
Ещё немного настроек
Если вы хотите использовать пользовательские цвета для тёмной/светлой темы (например, тёмно-синий для тёмной и светло-синий для светлой), то создайте папку values-night и переопределите файл цветов. Также можно переопределить styles.xml и использовать пользовательские атрибуты. Таким образом, приложение всегда будет использовать цвета из values-night , когда включена тёмная тема, и наоборот. Вы также можете подготовить альтернативные ресурсы для тёмной темы. Например, в drawable-night .
Весь исходный код ищите здесь.
Источник