๐ Introduced in Android Dev Notes Link
- support change color on status bar
Dynamic Theme is a Material Design-based Theme Management System for Android Jetpack Compose. Up until now, changing the theme on Android has been a very difficult task. Dynamic Theme was created to make Android's theme management easy. Theming can be applied by simply adding 'ProvidesTheme' to the top-level declaration in Jetpack Compose.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DynamicThemeService.get().ProvidesTheme {
// Add Compose Functions
}
}
}
}
Since this theme management system is based on Material Designs, knowledge of the Material Design System is required to use this library.
Add the mavenCentral() on project level(root level) build.gradle file:
allprojects {
repositories {
mavenCentral()
}
}
Add dependency on module level build.gradle file:
dependencies {
// Dynamic Theme support for Material2
implementation "io.github.seyoungcho2:dynamic-theme-compose:0.0.3"
// Dynamic Theme support for Material3
implementation "io.github.seyoungcho2:dynamic-theme-compose-material3:0.0.3"
}
If using build.gradle.kts
dependencies {
// Dynamic Theme support for Material2
implementation("io.github.seyoungcho2:dynamic-theme-compose:0.0.3")
// Dynamic Theme support for Material3
implementation("io.github.seyoungcho2:dynamic-theme-compose-material3:0.0.3")
}
Table of Contents
The ThemeModelKey is used to register the ThemeModel and access the registered ThemeModel.
- ThemeModelKey can be declared by using the function on ThemeModelKey
val THEME_MODEL_KEY_BLUE = ThemeModelKey.of("Blue")
- ThemeModelKey.Default is predefined for the default theme. If the current theme is not set, then ThemeModelKey.Default is used to retrieve the ThemeModel. Alternatively, you can also access the default ThemeModel using it.
DynamicThemeService.get().getThemeModel(ThemeModelKey.Default)
The ThemeModel is a data class for saving themes. It contains three parameters:
- ColorPalette: Light mode and dark mode color combinations for the theme.
- Typography: Configurations of typography for the theme.
- Shapes: Shape configurations for the theme."
data class ThemeModel(
val colorPalette: ColorPalette = ColorPalette(),
val typography: Typography = Typography(),
val shapes: Shapes = Shapes()
)
ThemeModel looks same on Material2 and Material3, but inside ThemeModel is little bit different. It's caused by the classes used in Material2 and Material3 are different.
Check what your project is using and make ThemeModel
Material2 ThemeModel consists of three parameters: ColorPalette, Typography, Shapes.
The ColorPalette contains two parameters: 'lightModeColors' for the Light Theme and 'darkModeColors' for the Dark Theme. When the device is set to dark mode on system, the darkModeColors are automatically used.
data class ColorPalette(
val lightModeColors: Colors = LightModeColorPalette,
val darkModeColors: Colors = DarkModeColorPalette
)
Colors class is Material2 class which consist of primary, primaryVariant, secondary, secondaryVariant, background, surface, error, onPrimary, onSecondary, onBackground, onSurface, onError, isLight variables. You can find more about color system on Material2 Color System, Material2 Color Document
Typography contains design data for characters. This is also part of Material2 Typography System. You will probably see familiar things like h1, h2, h3, subtitle1, subtitle2, body1, body2. Which are used to build heirarchy of characters. See Material2 Typography
See Material2 Shapes document
Material3 ThemeModel consists of three parameters: ColorPalette, Typography, Shapes.
The ColorPalette contains two parameters: 'lightModeColors' for the Light Theme and 'darkModeColors' for the Dark Theme. When the device is set to dark mode on system, the darkModeColors are automatically used.
data class ColorPalette(
val lightModeColors: ColorScheme = DefaultLightColorPalette,
val darkModeColors: ColorScheme = DefaultDarkColorPalette
)
ColorScheme class is Material3 class which consist of 29 colors which are used for coloring the application. You can find more about color system on Material3 Color System, Material3 Color Document
Typography contains design data for characters. This is also part of Material3 Typography System. Material3 typography enables us to fine-tune control for designing texts. See Material3 Typography
See Material3 Shapes document
DynamicThemeService is initialized as a singleton object by using DynamicThemeService.init(applicationContext). You must initalize DynamicThemeService to use it.
class DynamicThemeApp : Application() {
override fun onCreate() {
super.onCreate()
DynamicThemeService.init(applicationContext)
}
}
After initialized DynamicThemeService can be accessed by using DynamicThemeService.get().
val dynamicThemeService: DynamicThemeService = DynamicThemeService.get()
Dynamic has following features:
- Register Themes
- Get Registered Themes
- Set Current Theme
- Get Current Theme
- Provide Theme Composable with Current Theme
- Provide Theme Composable with ThemeModel
- How access theme variables on Composable
Registering both single and multiple theme supported. Default theme can also be changed.
DynamicThemeService.get().apply {
registerThemeModel(
ThemeModelKey.of("Pink"), ThemeModel(
colorPalette = ColorPalette(
lightModeColors = ColorPalettes.PinkColorPalette,
darkModeColors = ColorPalettes.PinkColorPalette,
),
shapes = Shapes.DEFAULT_ROUNDED_SHAPE
)
)
registerThemeModel(
ThemeModelKey.of("Blue"), ThemeModel(
colorPalette = ColorPalette(
lightModeColors = ColorPalettes.BlueColorPalette,
darkModeColors = ColorPalettes.BlueColorPalette,
)
)
)
}
DynamicThemeService.get().apply {
registerThemeModels(ThemeModels.getSupportedThemeModels())
}
fun getSupportedThemeModels(): Map<ThemeModelKey, ThemeModel> = mapOf(
THEME_MODEL_KEY_DEFAULT to THEME_MODEL_DEFAULT,
THEME_MODEL_KEY_BLACK to THEME_MODEL_BLACK,
THEME_MODEL_KEY_PINK to THEME_MODEL_PINK,
THEME_MODEL_KEY_BLUE to THEME_MODEL_BLUE,
THEME_MODEL_KEY_WHITE to THEME_MODEL_WHITE
)
DynamicThemeService.get().apply {
registerThemeModel(
ThemeModelKey.Default, ThemeModel(
colorPalette = ColorPalette(
lightModeColors = ColorPalettes.BlueColorPalette,
darkModeColors = ColorPalettes.BlueColorPalette,
)
)
)
}
DynamicThemeService.get().getThemeModel(themeModelKey)
val registeredThemes: Map<ThemeModelKey, ThemeModel> = DynamicThemeService.get().getRegisteredThemes()
suspend fun setCurrentTheme(themeModelKey: ThemeModelKey){
DynamicThemeService.get().setCurrentTheme(themeModelKey)
}
val currentThemeModel: ThemeModel = async { DynamicThemeService.get().getCurrentThemeModel() }.await()
val currentThemeModelFlow: Flow<ThemeModel> = DynamicThemeService.get().currentThemeModel
DynamicThemeService.get().ProvidesTheme {
// Write Composable Functions
}
DynamicThemeService.get().ProvidesTheme(themeModel) {
// Write Composable Functions
}
- Accessing color can be done by using 'MaterialTheme.colors.[Color Name]'
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
)
- Accessing typography can be done by using 'MaterialTheme.typography.[Typography Name]'
Text(
text = "Themes",
style = MaterialTheme.typography.h5
)
- Accessing shapes can be done by using 'MaterialTheme.shapes.[Shape Name]'
Box(
modifier = Modifier
.fillMaxSize()
.clip(MaterialTheme.shapes.medium)
)
- Accessing color can be done by using 'MaterialTheme.colorScheme.[Color Name]'
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
)
- Accessing typography can be done by using 'MaterialTheme.typography.[Typography Name]'
Text(
text = "Themes",
style = MaterialTheme.typography.bodyLarge
)
- Accessing shapes can be done by using 'MaterialTheme.shapes.[Shape Name]'
Card(
modifier = modifier,
shape = MaterialTheme.shapes.extraLarge
)
- Support it by making starโญ!
You can see stargazers here. - Also, follow me on GitHub for further updates
Designed and developed by 2023 seyoungcho2 (Seyoung Cho)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.