Android 10 introduced an exciting new user feature: Dark theme. While support for dark theme is not new to Android, Android 10 introduced a system-level toggle that switches between dark and light themes. That means the theme applies to the system UI as well, not only specific apps.
Now that your users have a system-level dark theme toggle, they’ll expect your app to support it. The choice is up to you, but not supporting it may lead to angry users. Unless your app design is already dark, it’s a good idea to go ahead and add it.
There are three major benefits of implementing dark theme in your app:
- Battery life: On devices with OLED screens, dark theme can extend battery life because the individual pixels have to do less work on dark areas of the screen.
- Visibility: Dark theme offers a better viewing experience in low-light environments.
- Accessibility: Dark theme is an important feature for users sensitive to bright light.
The sample app in this tutorial uses the MVVM architectural pattern. If you’re not familiar with this pattern, please go through our MVVM on Android video course to familiarize yourself with it.
The sample app also uses Koin for dependency injection. Understanding Koin isn’t necessary for this tutorial, but if you want to learn more about it, check out our Dependency Injection with Koin screencast.
In this tutorial, you’ll add dark theme support to the PdfFever app, which lets you read files in PDF format. It’s common for reader apps to have both light and dark themes to provide the best reading experience under various conditions and environments.
For the sake of simplicity, PdfFever comes bundled with predefined PDF files that you can read.
Download the materials for the tutorial by using the Download Materials button at the top or bottom of the page, and import the starter project into Android Studio. This is what the package structure of the project looks like:
Take a moment to familiarize yourself with the source code.
When you’re ready, build and run the app on a device or emulator running Android 10. You should see the home screen:
Tap on any of the listed PDF files to open the reader screen.
Pull down the Android Quick Settings menu, where you’ll see a Dark Theme toggle:
If you don’t see it, go to the Settings app and find the Dark Theme option there.
Enable a dark theme using this switch and you’ll see that the system UI switched to dark mode, but PdfFever stayed the same. Not such a good UX, right? :]
The quickest solution for implementing a dark theme is Force Dark, a new feature available from Android 10 that automatically applies the dark theme to your app.
There’s a way for users to enable the dark theme in your app, even if you don’t support it: by using the Override force-dark option in the Developer options. You could preview how Force Dark will look in your app by using this option.
Instead of previewing, you’re going to implement Force Dark in PdfFever.
Force Dark runs in the rendering time and inspects the rendered views. It then decides which views it should invert to adapt to dark mode.
Before implementing Force Dark, make sure you’ve configured your project for Android 10. Check that you’ve downloaded Android 10 SDK and that you’ve set
targetSdkVersion to 29. PdfFever comes this way out of the box.
To implement Force Dark, open styles.xml and add the following tag to the
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
forceDarkAllowed to the
AppTheme and setting it to
true, you apply Force Dark throughout the whole app. You can also add it to specific activities instead of the entire app.
That’s it. You successfully implemented Force Dark. Build and run your app and enable Dark Theme in the system settings to see the result.
Looks pretty good.
Adding Force Dark only requires one line of code, but there are two problems: You have almost no control over how your app will look after you apply it and it only works for Android 10.
If you want to disable Force Dark for specific views, you can do so by adding a
android:forceDarkAllowed attribute to the view in the XML. You can also use
setForceDarkAllowed() to do so programmatically.
For simple apps, Force Dark might work well enough. But while you can use it as a temporary solution until you properly implement the dark theme, it’s not sufficient for many apps. An example would be an image inside a view, this image may not look suitable if it is automatically rendered into dark mode.
The other option to add a dark theme is to implement a custom theme.
DayNight is a theme in the
AppCompat library that lets you implement a custom dark theme in your app.
DayNight enables a
night resource qualifier, which means that you can use specific resource folders like
values-night. It’s backwards compatible up to API 14.
To add DayNight to your app, open styles.xml.
First, comment out the line that enables the ForceDark feature.
Then, make your
AppTheme extend the DayNight theme by changing the value of the parent attribute of the
AppTheme style tag to
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
DayNight from the MaterialComponents library, which is a part of Android Jetpack that helps developers implement material design in their app.
If you're not familiar with material design, check out our Introduction to Material Design tutorial.
The best practice is to use MaterialComponents over the AppCompat library because it redesigns some UI elements and adds some new elements to the collection.
DayNight provides platform attributes like
textColorPrimary, which automatically adapts to the dark or light theme.
For your next step, you're going to add your own colors instead of relying on platform attributes.