A Compose Multiplatform library for creating dynamic Material Design 3 color palettes from any color.
Check out MaterialKolor Builder to see MaterialKolor in action and generate your own color schemes. It can export to MaterialKolor code, or plain Material 3 code.
The KDoc is published at docs.materialkolor.com
This library is written for Compose Multiplatform, and can be used on the following platforms:
- Android
- iOS
- JVM (Desktop)
- JavaScript/wasm (Browser)
You can see it in action by using MaterialKolor Builder.
The heart of this library comes from the material-color-utilities repository. It is currently only a Java library, and I wanted to make it available to Kotlin Multiplatform projects. The source code was taken and converted into a Kotlin Multiplatform library.
I also incorporated the Compose ideas from another open source library m3color.
You can add this library to your project using Gradle.
To add to a multiplatform project, add the dependency to the common source-set:
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("com.materialkolor:material-kolor:2.0.0")
}
}
}
}
For an Android only project, add the dependency to app level build.gradle.kts
:
dependencies {
implementation("com.materialkolor:material-kolor:2.0.0")
}
[versions]
materialKolor = "2.0.0"
[libraries]
materialKolor = { module = "com.materialkolor:material-kolor", version.ref = "materialKolor" }
To generate a custom ColorScheme
you simply need to call dynamicColorScheme()
with your target
seed color:
@Composable
fun MyTheme(
seedColor: Color,
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = rememberDynamicColorScheme(seedColor, useDarkTheme)
MaterialTheme(
colors = colorScheme.toMaterialColors(),
content = content
)
}
You can also pass in
a PaletteStyle
to
customize the generated palette:
dynamicColorScheme(
seedColor = seedColor,
isDark = useDarkTheme,
style = PaletteStyle.Vibrant,
)
A DynamicMaterialTheme
Composable is also available. It is a wrapper around MaterialTheme
that
uses dynamicColorScheme()
to generate a ColorScheme
for you. You can animate the color scheme by
passing in animate = true
.
Example:
@Composable
fun MyTheme(
seedColor: Color,
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
DynamicMaterialTheme(
seedColor = seedColor,
isDark = useDarkTheme,
animate = true,
content = content
)
}
Included in the library are some extensions for working with colors. You can check out the /ktx package for more information.
But here are a couple useful examples:
If you want to harmonize a color with another you can use the Color.harmonize()
function. You can
read more about color harmonization on
the Material 3 Documentation.
Example:
val newColor = MaterialTheme.colorScheme.primary.harmonize(Color.Blue)
There is an additional function specifically for harmonizing with the primary color:
val newColor = Color.Blue.harmonizeWithPrimary()
Note: Color.harmonize()
has an optional parameter matchSaturation
which when set to true
will adjust the saturation from the other color.
You can lighten or darken a color using the Color.lighten()
and Color.darken()
functions.
For example:
val newColor = MaterialTheme.colorScheme.primary.lighten(0.2f)
Check out the demo app for a full example.
You can determine if a Color
is warm or cold using the following:
val isWarm = MaterialTheme.colorScheme.primary.isWarm()
val isCold = MaterialTheme.colorScheme.primary.isCold()
You can calculate a seed color, or colors that are suitable for UI theming from an image. This is useful for generating a color scheme from a user's profile picture, or a background image.
To do so you can call ImageBitmap.themeColors()
, ImageBitmap.themeColor()
or the @Composable
function rememberThemeColors()
or rememberThemeColor()
:
fun calculateSeedColor(bitmap: ImageBitmap): Color {
val suitableColors = bitmap.themeColors(fallback = Color.Blue)
return suitableColors.first()
}
See ImageBitmap.kt
for more information.
Or in Compose land:
@Composable
fun DynamicTheme(image: ImageBitmap, content: @Composable () -> Unit) {
val seedColor = rememberThemeColor(image, fallback = MaterialTheme.colorScheme.primary)
AnimatedDynamicMaterialTheme(
seedColor = seedColor,
content = content
)
}
For a more advanced use-case you can use my other library kmPalette.
You can get the dominant color from an image, or you can also generate a color palette.
Follow the instructions there to set it up, then as an example. You can use it to generate a color theme from a remote image:
@Composable
fun SampleTheme(
imageUrl: Url, // Url("http://example.com/image.jpg")
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit,
) {
val networkLoader = rememberNetworkLoader()
val dominantColorState = rememberDominantColorState(loader = networkLoader)
LaunchedEffect(imageUrl) {
dominantColorState.updateFrom(imageUrl)
}
AnimatedDynamicMaterialTheme(
seedColor = dominantColorState.color,
isDark = useDarkTheme,
content = content
)
}
The module material-color-utilities
is licensed under the Apache License, Version 2.0. See
their LICENSE and their
repository here for more
information.
- Convert Java code to Kotlin
- Convert library to Kotlin Multiplatform
For the remaining code see LICENSE for more information.