Android Jetpack Compose Material3 Colors and dark theme
In this article, we will explore how to customize the colors of an Android app using material3 theme.
We will use a Mars Rover Explorer as an example. This app has 3 screens. The first allows the user to choose the rover. The second screen the sol (the day on Mars according to the mission). The third will display a list of photos.
The user can save/unsave photos. And then access it on a fourth screen by the bottom nav.
This app is uses for my Udemy course about Jetpack Compose, available for free with this link.
A previous story explains how to create an architecture with Data Layer, Repository and ViewModel.
Below is the expected result for the light theme:
And the display for the dark theme:
First, we need to define some colors in the Colors.kt file.
val Orange80 = Color(0xFFBF360C)
val DarkOrange = Color(0xFF500000)
val Pink80 = Color(0xFFEFB8C8)
val Orange40 = Color(0xFFBF360C)
val Orange10 = Color(0xFFFFCCBC)
val Pink40 = Color(0xFF7D5260)
val LightYellow = Color(0xFFFFCC80)
In the Theme.kt file, create a private val DarkColorScheme by using the method darkColorScheme().
private val DarkColorScheme = darkColorScheme(
primary = Orange80,
secondary = DarkOrange,
surfaceVariant = DarkOrange,
tertiary = Pink80,
onSecondary = Color.White
)
Also, create a LightColorScheme with the method lightColorScheme().
private val LightColorScheme = lightColorScheme(
primary = Orange40,
secondary = Orange10,
tertiary = Pink40,
surfaceVariant = LightYellow
)
Then create a val colorScheme with the DarkColorScheme or LightColorScheme according to the value of isSystemInDarkTheme().
//constructor parameter
darkTheme: Boolean = isSystemInDarkTheme()
//...
val colorScheme = when {
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
If you create a default project with material3, it will include a dynamic theme for Android 13. Because if you do not want to use this feature remove those lines for the first condition in the when.
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
At the end, apply the colorScheme to the MaterialTheme.
MaterialTheme(
colorScheme = colorScheme,
typography = MarsRoverTypography,
content = content
)
Now if we run the application, we obtain the result except for the save/unsave icon. This icon remains black when the dark mode is activated.
To change the color of the icon, we need to use the old way and create two different resources, one for the light mode in values/colors.xml.
<resources>
<color name="icon_color">#FF000000</color>
</resources>
The other in values-night/colors.xml for the dark mode.
<resources>
<color name="icon_color">#FFFFFFFF</color>
</resources>
Then use this value in the vector drawable for the tint value.
<vector android:tint="@color/icon_color">
</vector>
In the Mars Rover Explorer, we have two drawables drawable/ic_save.xml and drawable/ic_save_outline.xml. The first is filled representing the saved status, the second is the outline icon representing a not-saved photo.
Now we have all the texts, and the icons are white in dark mode and black in light mode.
If you want to learn how to create this app step by step, a complete live coding course with Jetpack Compose with Hilt, Room and Retrofit is available for free on Udemy.
The code with Jetpack Compose, Hilt, Retrofit and Room is on Github.