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
theme
package. For example,com.sababado.ui.theme
. This keeps everything organized as if it were kept in theres
directory.
The Material Color Tool can help identify a basic color scheme.
- Color definitions belong in a
theme.Color
file. - Use "litaral" color names rather than "semantic" colors, as these may be used in multiple places. For example
Red700
vsPrimary
.Red
andLightishRed
may 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,
primary
colors are used to color a container, whereas in dark mode thesurface
color is used. TheprimarySurface
color 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 theprimarySurface
color. 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/font
directory 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.Type
ortheme.Typography
file 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.kt
file, and override what it needs to be different from Material. - Define the lists
lightColors
anddarkColors
here. 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
MaterialTheme
objects are referenced to customize UI as needed.