Composable UI is themed by default with a MaterialTheme object. It consists of three primary parts:
- Color
- Typography
- Shapes Each of these has a pre-defined structure that, when used properly, will make theming, branding, and non-functional UI changes a breeze. The intent is to encourage use of a small, consistent set of styles to make things more maintainable. Here are some considerations if your theme does not include a baseline purple color scheme, Roboto type scale, and slightly rounded shapes. Google provides an interactive codelab for anyone interested in getting a bit of practice. This codelab does not teach Jetpack Compose, but rather highlights organization and best practices of themes. Below are some high points. All Jetpack Compose lessons are here.
Some best practices and rules for the road:
- Keep all theme files in a
themepackage. For example,com.sababado.ui.theme. This keeps everything organized as if it were kept in theresdirectory.
The Material Color Tool can help identify a basic color scheme.
- Color definitions belong in a
theme.Colorfile. - Use "litaral" color names rather than "semantic" colors, as these may be used in multiple places. For example
Red700vsPrimary.RedandLightishRedmay be okay. - Automatically set a high / medium / none alpha on text based on heirarchy (top to bottom) using the
CompositionLocalProvider. - By default: in light mode,
primarycolors are used to color a container, whereas in dark mode thesurfacecolor is used. TheprimarySurfacecolor in light mode can also be used explicitely on a surface (like aTopAppBar) to make it more clear. In other words… color a surface with theprimarySurfacecolor. The color pallete provided:
Colors(
primary: Color?,
primaryVariant: Color?,
secondary: Color?,
secondaryVariant: Color?,
background: Color?,
surface: Color?,
error: Color?,
onPrimary: Color?,
onSecondary: Color?,
onBackground: Color?,
onSurface: Color?,
onError: Color?,
isLight: Boolean?
)Details on each individual color.
Don't use raw colors in files and classes
Surface(color = Color.LightGray) {
Text(
text = "Hard coded colors don't respond to theme changes :(",
textColor = Color(0xffff00ff)
)
}Always reference a color by the theme. For example:
Surface(color = MaterialTheme.colors.primary)
Colors can be copied in specific places if needed, but should always be based on a theme color.
val derivedColor = MaterialTheme.colors.onSurface.copy(alpha = 0.1f)
Notice that the MaterialTheme colors class and variables are referenced everywhere in code. Once a custom theme is set, it overrides these variables. This is why it's extra important to stick to theming.
At the time of writing (Feb 2022), Jetpack Compose does not support pulling directly from Android's Downloadable Fonts. The Type Scale Tool can help generate code for specific fonts.
- Any custom fonts used will have to be saved to the
res/fontdirectory and can be loaded in. The type system is similar to what can be found on most text editors (like MS Word). Some of the basic configurations include: - Scale Category (header1, body, button, subtitle, caption, etc)
- ypeface
- Weight
- Size
- Case
- Letter spacing
- And more!
Today, the font should be created in a
theme.Typeortheme.Typographyfile and referenced in the theme. Text styles can be referenced the same way as colors.
Use the Shape Customization Tool to help visualize corner and radius changes on various UI examples.
Shapes are based on rounded corners or cut corners.
Shape styles can be refereced from the MaterialTheme object just like colors and typography.
In xml based Android UI, styles can be extracted an reused in various components and UI elements without much restriction. This can lead to a disorganized mess of one-off and just barely slightly unique styles that offer little-to-no gain. And so, compose does not offer an explicit way to extract styles like Android View styles or css styles. Everything is written in Kotlin and the best way to achieve the same goal is to create a library of customized components to be used throught the app.
For example a Header style to be used anywhere a header is needed. Colors, typography, and shapes are the building blocks to these components.
This is where it all comes together. Colors, typography, and shapes help define a theme and build it's various components.
- Each theme should be in a
Theme.ktfile, and override what it needs to be different from Material. - Define the lists
lightColorsanddarkColorshere. These are theme specific lists of colors and should not be placed with the rest of the individual colors. - Custom themes are not referenced throughout the app. Instead, once a custom theme is set, the
MaterialThemeobjects are referenced to customize UI as needed.