Anatomía de un tema en Compose

En Jetpack Compose, los temas se componen de varias construcciones de nivel inferior y API relacionadas. Estos elementos se pueden ver en el código fuente de MaterialTheme y también se pueden aplicar en sistemas de diseño personalizados.

Clases del sistema de temas

Por lo general, un tema está compuesto por varios sistemas que agrupan conceptos visuales y de comportamiento comunes. Esos sistemas se pueden modelar con clases que tienen valores de temas.

Por ejemplo, MaterialTheme incluye Colors (sistema de colores), Typography (sistema de tipografía) y Shapes (sistema de formas).

@Immutable
data class ColorSystem(
    val color: Color,
    val gradient: List<Color>
    /* ... */
)

@Immutable
data class TypographySystem(
    val fontFamily: FontFamily,
    val textStyle: TextStyle
)
/* ... */

@Immutable
data class CustomSystem(
    val value1: Int,
    val value2: String
    /* ... */
)

/* ... */

Composición local del sistema de temas

Las clases del sistema de temas se proporcionan de forma implícita al árbol de composición como instancias de CompositionLocal. Esto permite que se haga referencia de manera estática a los valores de tema en las funciones que admiten composición.

Si quieres obtener más información acerca de CompositionLocal, consulta la Guía de alcance local con composición de CompositionLocal.

val LocalColorSystem = staticCompositionLocalOf {
    ColorSystem(
        color = Color.Unspecified,
        gradient = emptyList()
    )
}

val LocalTypographySystem = staticCompositionLocalOf {
    TypographySystem(
        fontFamily = FontFamily.Default,
        textStyle = TextStyle.Default
    )
}

val LocalCustomSystem = staticCompositionLocalOf {
    CustomSystem(
        value1 = 0,
        value2 = ""
    )
}

/* ... */

Función de tema

La función de tema es el punto de entrada y la API principal. Construye instancias de los CompositionLocal de los sistemas de temas, mediante valores reales de cualquier lógica necesaria, que se proporcionan al árbol de composición con CompositionLocalProvider. El parámetro content permite que los elementos componibles anidados accedan a los valores de temas relacionados con la jerarquía.

@Composable
fun Theme(
    /* ... */
    content: @Composable () -> Unit
) {
    val colorSystem = ColorSystem(
        color = Color(0xFF3DDC84),
        gradient = listOf(Color.White, Color(0xFFD7EFFF))
    )
    val typographySystem = TypographySystem(
        fontFamily = FontFamily.Monospace,
        textStyle = TextStyle(fontSize = 18.sp)
    )
    val customSystem = CustomSystem(
        value1 = 1000,
        value2 = "Custom system"
    )
    /* ... */
    CompositionLocalProvider(
        LocalColorSystem provides colorSystem,
        LocalTypographySystem provides typographySystem,
        LocalCustomSystem provides customSystem,
        /* ... */
        content = content
    )
}

Objeto de tema

El acceso a los sistemas de temas se realiza mediante un objeto con propiedades útiles. Para mantener la coherencia, el objeto tiende a llamarse de la misma forma que la función del tema. Las propiedades simplemente obtienen la composición actual de forma local.

// Use with eg. Theme.colorSystem.color
object Theme {
    val colorSystem: ColorSystem
        @Composable
        get() = LocalColorSystem.current
    val typographySystem: TypographySystem
        @Composable
        get() = LocalTypographySystem.current
    val customSystem: CustomSystem
        @Composable
        get() = LocalCustomSystem.current
    /* ... */
}