Creating and using a material theme in Jetpack Compose is simple, and setting up your own colors, typography, and shapes can be done in a matter of minutes. Material design defines 12 color variables, but the docs don't make it clear how they can be extended.
Suppose we want to add
onWarning colors to complement the built-in
onError. The most straightforward approach would be to define the new colors globally and refer to them in our layout. But if we want them to change dynamically with our theme we need something more sophisticated. Let's get to it!
First of all, we need something like the Colors class, which holds all the theme color values. We can’t extend the built-in class, but in the spirit of compose we can make a new class composed of the material colors and our new colors:
The result is a class that functions just like
Colors but has two additional values. Next, let’s set up some light and dark color palettes:
With the palettes in place, we can create our theme. This will look similar to the code generated by the Android Studio new project wizard, but with a few important differences:
The first thing to note is
LocalColors. This is a CompositionLocal, and I won't go into detail on how it works. But in short, it will allow us to access the colors defined by the current theme without having to pass them as arguments down our layout tree.
Inside our theme, we select the color palette as usual and assign its material colors to the
MaterialTheme so they are still applied correctly.
CompositionLocalProvider defines a scope within which our
LocalColors will be provided.
Finally, we need a way to access these colors easily from our composable functions.
That’s it! We can now easily access all colors using
MaterialTheme.myColors and build UI:s that respond to theme changes with all the colors we need. As a bonus, this method can also be applied to extend typography and shapes!
Finally here is a simple demo that demonstrates our new warning colors in action: