Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Temas en Compose

Jetpack Compose facilita la implementación de un estilo uniforme para tu app mediante la aplicación de temas. Puedes personalizar la implementación de Material Design de Compose para que se adapte a la marca de tu producto. Si no se adapta a tus necesidades, puedes crear un sistema de diseño personalizado con las API públicas de Compose.

Temas para toda la aplicación

Jetpack Compose ofrece una implementación de Material Design, un sistema de diseño integral para la creación de interfaces digitales. Los componentes (botones, tarjetas, interruptores, etc.) de Material Design se compilan sobre la aplicación de temas de Material, que es una forma sistemática de personalizar Material Design para que refleje mejor la marca de tu producto. Un tema de Material comprende atributos de color, tipografía y forma. Cuando personalizas esos atributos, tus cambios se reflejan automáticamente en los componentes que usas para compilar tu app.

Jetpack Compose implementa esos conceptos con el elemento que admite composición MaterialTheme:

MaterialTheme(
  colors = …,
  typography = …,
  shapes = …
) {
  // app content
}

Configura los parámetros que pasas a MaterialTheme para aplicar un tema a tu aplicación.

Dos capturas de pantalla que contrastan. La primera usa el estilo predeterminado de MaterialTheme, mientras que la segunda usa un estilo modificado.

Figura 1: La primera captura de pantalla muestra una app que no configura MaterialTheme y, por lo tanto, usa el estilo predeterminado. La segunda, muestra una app que pasa parámetros a MaterialTheme para personalizar el estilo.

Color

Los colores se modelan en Compose con la clase Color, una clase simple que retiene datos.

val red = Color(0xffff0000)
val blue = Color(red = 0f, green  0f, blue = 1f)

Si bien puedes organizarlos como te guste (como constantes de nivel superior, dentro de un singleton o intercalado definido), te recomendamos que especifiques los colores en tu tema y los recuperes desde allí. Este enfoque permite admitir varios temas, como el tema oscuro.

Ejemplo de paleta de colores de un tema

Compose proporciona la clase Colors para modelar el sistema de colores de Material. Colors ofrece funciones de compilador para crear conjuntos de colores claros u oscuros:

private val yellow200 = Color(0xffffeb46)
private val blue200 = Color(0xff91a4fc)
…

private val DarkColors = darkColors(
  primary = yellow200,
  secondary = blue200,
  …
)
private val LightColors = lightColors(
  primary = yellow500,
  primaryVariant = yellow400,
  secondary = blue700,
  …
)

Una vez que hayas definido tus Colors, puedes pasarlos a un MaterialTheme:

MaterialTheme(
  colors = if (darkTheme) DarkColors else LightColors,
  typography = …,
  shapes = …
) {
  // app content
}

Cómo usar colores de tema

Puedes recuperar los Colors proporcionados al elemento que admite compilación de MaterialTheme con MaterialTheme.colors.

Text(
  text = "Hello theming",
  color = MaterialTheme.colors.primary
)

Color de contenido y superficie

Muchos componentes aceptan un par de color y "color del contenido":

Surface(
  color: Color = MaterialTheme.colors.surface,
  contentColor: Color = contentColorFor(color),
  …

TopAppBar(
  backgroundColor: Color = MaterialTheme.colors.primarySurface,
  contentColor: Color = contentColorFor(backgroundColor),
…

Esto te permite no solo definir el color de un elemento que admite composición, sino también proporcionar un color predeterminado para su contenido, es decir, los elementos que admiten composición que este contiene. Muchos elementos que admiten composición usan este color de contenido de forma predeterminada. Por ejemplo, Text basa su color en el color de contenido del elemento principal, y Icon usa ese color para establecer su tono.

Dos ejemplos del mismo banner, con colores distintos

Figura 2: Al establecer diferentes colores de fondo, se producen distintos colores de texto y de ícono.

El método contentColorFor() recupera el color adecuado para mostrar "arriba" de cualquier color de tema. Por ejemplo, si configuras un fondo primary, se establece onPrimary como color de contenido. Si configuras un color de fondo que no pertenece a ningún tema, también debes especificar un color de contenido apropiado. Usa la función contentColor() para recuperar el color de contenido actual que contrasta con el fondo actual.

Énfasis

El énfasis te permite mostrar visualmente la importancia relativa de un componente mediante la modificación del Alfa de contentColor(). Establecer el énfasis facilita y unifica la configuración de los componentes mediante la asignación y el uso de EmphasisLevels:

// Both Icon & Text use contentColor() by default; this will alter its alpha
ProvideEmphasis(emphasis = EmphasisAmbient.current.high) {
    Text(…)
}
ProvideEmphasis(emphasis = EmphasisAmbient.current.medium) {
    Icon(…)
    Text(…)
}

Captura de pantalla del título de un artículo, en el que se muestran diferentes niveles de énfasis

Figura 3: Aplica diferentes niveles de énfasis en el texto para comunicar visualmente la jerarquía de la información.

Tema oscuro

En Compose, debes proporcionar diferentes conjuntos de Colors al elemento que admite composición MaterialTheme y consumir colores a través del tema para implementar temas claros y oscuros:

@Composable
fun MyTheme(
  darkTheme: Boolean = isSystemInDarkTheme(),
  content: @Composable () -> Unit
) {
  MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors,
    typography = …,
    shapes = …,
    content = content
  )
}

En este ejemplo, MaterialTheme se une a su propia función que admite composición y que acepta un parámetro que especifica si se debe usar un tema oscuro o no. En este caso, la función consulta a la configuración de tema del dispositivo para obtener el valor predeterminado de darkTheme.

Cuando implementas un tema oscuro, puedes verificar si los Colors actuales son claros u oscuros:

val isLightTheme = MaterialTheme.colors.isLight

Este valor lo establecen las funciones del compilador lightColors() y darkColors().

En Material, las superficies en temas oscuros con mayor elevación reciben superposiciones de elevación, lo que ilumina su fondo. A esas superposiciones las implementa de forma automática el elemento que admite composición Surface cuando se usan colores oscuros:

Surface(
  elevation = 2.dp,
  color = MaterialTheme.colors.surface, // color will adjusted for elevation
  …

Captura de pantalla de una app, que muestra la diferencia sutil de los colores que se usan para los elementos que se encuentran a diferentes niveles de elevación

Figura 4: Las tarjetas y la navegación inferior tienen un color de surface como el del fondo, pero como están a una elevación mayor, es un poco más claro.

Cómo extender colores de Material

Compose modela cuidadosamente el tema cromático de Material para que los lineamientos correspondientes sean simples y seguros de seguir. Si necesitas extender el conjunto de colores, puedes implementar tu propio sistema de colores, como se muestra a continuación, o bien agregar extensiones:

@Composable
val Colors.snackbarAction: Color
  get() = if (isLight) Red300 else Red700

Tipografía

Material define un sistema de tipos, y te recomienda usar una pequeña cantidad de estilos con nombres semánticos.

Ejemplo de varios tipos de letra en distintos estilos

Compose implementa el sistema de tipos con Typography, TextStyle y clases relacionadas con la fuente. El constructor Typography ofrece valores predeterminados para cada estilo, de modo que puedes omitir cualquiera que no quieras personalizar:

private val Rubik = fontFamily(
    font(R.font.rubik_regular),
    font(R.font.rubik_medium, FontWeight.W500),
    font(R.font.rubik_bold, FontWeight.Bold)
)

private val MyTypography = Typography(
  h1 = TextStyle(
    fontFamily = Rubik,
    fontWeight = FontWeight.W300,
    fontSize = 96.sp
  ),
  body1 = TextStyle(
    fontFamily = Rubik,
    fontWeight = FontWeight.W600,
    fontSize = 16.sp
  )
  …
)
MaterialTheme(typography = MyTypography, …)

Si deseas usar siempre la misma fuente, especifica el parámetro defaultFontFamily y omite el objeto fontFamily de cualquier elemento TextStyle:

val typography = Typography(defaultFontFamily = Rubik)
MaterialTheme(typography = typography, …)

Cómo usar estilos de texto

Recupera TextStyle del tema, como se muestra en este ejemplo:

Text(
    text = "Subtitle2 styled"
    style = MaterialTheme.typography.subtitle2
)

Captura de pantalla que muestra distintos tipos de letra combinados para diferentes fines

Figura 5: Usa una selección de tipos de letra y estilos para expresar tu marca.

Forma

Material define un sistema de formas, lo que te permite definir formas para componentes grandes, medianos y pequeños.

Muestra una variedad de formas de Material Design

Compose implementa el sistema de formas con la clase Shapes, que te permite especificar una CornerBasedShape para cada categoría:

val Shapes = Shapes(
  small = RoundedCornerShape(percent = 50),
  medium = RoundedCornerShape(0f),
  large = CutCornerShape(
    topLeft = 16.dp,
    topRight = 0.dp,
    bottomRight = 0.dp,
    bottomLeft = 16.dp
  )
)

MaterialTheme(shapes = Shapes, …)

Muchos componentes usan estas formas de manera predeterminada. Por ejemplo, Button, TextField y FloatingActionButton, de manera predeterminada, adoptan el valor pequeño, AlertDialog adopta el valor mediano y ModalDrawerLayout el grande. Consulta la referencia del esquema de formas para ver la asignación completa.

Cómo usar formas

Recupera las formas del tema:

Surface(
  shape = MaterialTheme.shapes.medium …
) {
  ...
}

Captura de pantalla de una app que usa formas de Material para transmitir en qué estado se encuentra un elemento

Figura 6: Usa formas para expresar la marca o el estado.

Estilos de componente

No hay un concepto explícito de estilos de componente en Compose, y debes crear tus propios elementos que admiten composición para brindar esta función. Por ejemplo, para crear un estilo de botón, une un botón a tu propia función que admite composición, configura directamente los parámetros que deseas modificar y expón otros como parámetros al elemento que admite composición que esta contiene.

@Composable
fun LoginButton(
  onClick: () -> Unit,
  modifier: Modifier = Modifier,
  text: @Composable () -> Unit) {
  Button(
    backgroundColor = MaterialTheme.colors.secondary,
    onClick = onClick,
    modifier = modifier,
    text = text
  }
}

Sistemas de diseño personalizado

Si bien recomendamos el sistema de diseño Material y Jetpack Compose viene con una implementación incluida, no es obligatorio que lo uses. Es perfectamente posible que crees tu propio sistema de diseño de la misma manera. Material está íntegramente compilado sobre API públicas que puedes usar para lograrlo.

El alcance de este documento no incluye brindar una descripción completa de cómo compilar un sistema de diseño personalizado, pero puedes consultar los siguientes recursos:

Más información

Para obtener más información, prueba el codelab de temas de Jetpack Compose.