Jetpack Compose ofrece una implementación de Material Design, un sistema de diseño integral para crear interfaces digitales. Los componentes de Material Design (botones, tarjetas, interruptores, etcétera) se basan en los temas de Material, que son una forma sistemática de personalizar Material Design para reflejar mejor la marca de tu producto. Un tema de Material contiene atributos de color, tipografía y forma. Cuando personalizas estos atributos, los cambios se reflejan automáticamente en los componentes que usas para compilar tu app.
Jetpack Compose implementa esos conceptos con el elemento MaterialTheme que admite composición:
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Configura los parámetros que pasas a MaterialTheme para aplicar un tema a tu aplicación.
Color
Los colores se modelan en Compose con la clase Color, una clase que contiene 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 el tema oscuro y los temas anidados.
Compose proporciona la clase Colors para modelar el sistema de colores de Material. Colors proporciona funciones de compilador para crear conjuntos de colores claros o 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, // ... )
Después de definir tus Colors, puedes pasarlos a un MaterialTheme:
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Usa los colores del 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 = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Esto te permite no solo definir el color de un elemento componible, sino también proporcionar un color predeterminado para el contenido, es decir, los elementos componibles que 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.
El método contentColorFor() recupera el color "activado" adecuado para cualquier color de tema. Por ejemplo, si estableces un color de fondo primary en Surface, se usa esta función para establecer onPrimary como el color del contenido.
Si configuras un color de fondo que no pertenece a ningún tema, también debes especificar un color de contenido adecuado. Usa LocalContentColor para recuperar el color de contenido preferido para el fondo actual, en una posición determinada de la jerarquía.
Versión alfa de contenido
Muchas veces quieres variar la forma en que destacas el contenido para comunicar la importancia y ofrecer una jerarquía visual. Las recomendaciones de legibilidad de texto de Material Design aconsejan usar diferentes niveles de opacidad para transmitir distintos niveles de importancia.
En Jetpack Compose, esto se implementa con LocalContentAlpha. Puedes especificar una versión alfa de contenido para establecer una jerarquía proporcionando un valor para este objeto CompositionLocal. Los elementos componibles anidados pueden usar este valor para aplicar el tratamiento alfa a su contenido. Por ejemplo, Text y Icon de forma predeterminada utilizan la combinación de LocalContentColor ajustada para utilizar LocalContentAlpha. Material especifica algunos valores alfa estándar (high, medium y disabled), que están modelados por el objeto ContentAlpha.
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Para obtener más información sobre CompositionLocal, consulta Datos de alcance local con CompositionLocal.
ContentAlpha.high. La segunda línea contiene metadatos menos importantes y, por lo tanto, usa ContentAlpha.medium.Tema oscuro
En Compose, debes proporcionar diferentes conjuntos de Colors al elemento MaterialTheme que admite composición para implementar temas claros y oscuros:
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ 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.
Puedes usar código como el siguiente para verificar si los objetos Colors actuales son claros u oscuros:
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Superposiciones de elevación
En Material, las superficies con mayor elevación en los temas oscuros reciben superposiciones de elevación, que aclaran su fondo. Cuanto mayor sea la elevación de una superficie (acercándola a una fuente de luz implícita), más clara se volverá esa superficie.
El elemento Surface componible aplica estas superposiciones automáticamente cuando se usan colores oscuros, al igual que cualquier otro elemento componible de Material que use una superficie:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
surface como fondo. Como las tarjetas y la navegación inferior están en diferentes niveles de elevación por encima del fondo, tienen colores ligeramente diferentes: las tarjetas son más claras que el fondo y la navegación inferior es más clara que las tarjetas.Para situaciones personalizadas que no involucren un Surface, usa LocalElevationOverlay, un CompositionLocal que contenga el ElevationOverlay que usan los componentes Surface:
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Para inhabilitar las superposiciones de elevación, proporciona null en el punto elegido de una jerarquía de elementos que admiten composición:
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Acentuación de color limitada
Material recomienda aplicar acentuación de color limitada para los temas oscuros, prefiriendo el uso del color surface sobre el color primary en la mayoría de los casos. Los elementos de Material que admiten composición, como TopAppBar y BottomNavigation, implementan este comportamiento de forma predeterminada.
Para situaciones personalizadas, usa la propiedad de extensión primarySurface:
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Tipografía
Material define un sistema de tipos, lo que te anima a usar una pequeña cantidad de estilos con nombres semánticos.
Compose implementa el sistema de tipos con las clases Typography, TextStyle y relacionadas con las fuentes. El constructor Typography ofrece valores predeterminados para cada estilo, de modo que puedes omitir cualquier parámetro que no quieras personalizar:
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Si quieres usar el mismo tipo de letra en todo el texto, especifica el parámetro defaultFontFamily y omite el fontFamily de cualquier elemento TextStyle:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Usa estilos de texto
Se accede a los elementos TextStyle con MaterialTheme.typography. Recupera
los elementos TextStyle de la siguiente manera:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )

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

Compose implementa el sistema de formas con la clase Shapes, que te permite especificar un CornerBasedShape para cada categoría de tamaño:
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
Muchos componentes usan estas formas de manera predeterminada. Por ejemplo, Button, TextField y FloatingActionButton se establecen de forma predeterminada en pequeño, AlertDialog se establece de forma predeterminada en mediano y ModalDrawer se establece de forma predeterminada en grande. Consulta la referencia del esquema de formas para ver la asignación completa.
Usa formas
Se accede a los elementos Shape con MaterialTheme.shapes. Recupera los elementos Shape con un código como este:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
Estilos predeterminados
No hay un concepto equivalente en Compose de los estilos predeterminados de las vistas de Android. Puedes proporcionar una funcionalidad similar creando tus propias funciones de componibilidad overload que unan los componentes de Material. Por ejemplo, para crear un estilo de botón, une un botón en tu propia función de componibilidad, configura directamente los parámetros que deseas o necesitas modificar, y expón otros como parámetros al elemento componible que los contiene.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Superposiciones de temas
Puedes lograr el equivalente de las superposiciones de temas de las vistas de Android en Compose anidando elementos componibles MaterialTheme. Debido a que MaterialTheme establece los colores, la tipografía y las formas de forma predeterminada en el valor del tema actual, todos los demás parámetros conservan sus valores predeterminados cuando un tema solo establece uno de esos parámetros.
Además, cuando migres pantallas basadas en View a Compose, presta atención a los usos del atributo android:theme. Es probable que necesites un nuevo MaterialTheme
en esa parte del árbol de IU de Compose.
En este ejemplo, la pantalla de detalles usa un PinkTheme para la mayor parte de la pantalla y, luego, un BlueTheme para la sección relacionada. En la siguiente captura de pantalla y el código, se ilustra este concepto:
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
Estados de componentes
Los componentes de Material con los que se puede interactuar (con un clic o un botón de activación, etc.) pueden estar en diferentes estados visuales. Los estados incluyen habilitado, inhabilitado, presionado, etc.
Con frecuencia, los elementos que admiten composición tienen un parámetro enabled. Si se establece en false, se evita la interacción, y se cambian propiedades, como el color y la elevación, para transmitir, de forma visual, el estado del componente.
enabled = true (izquierda) y enabled = false (derecha).En la mayoría de los casos, puedes confiar en los parámetros predeterminados para valores como el color y la elevación. Si necesitas configurar valores que se usan en diferentes estados, hay clases y funciones de conveniencia disponibles. Considera el siguiente ejemplo de botón:
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
enabled = true (izquierda) y enabled = false (derecha), con valores de color y elevación ajustados.Ecos
Los componentes de Material usan ondas para indicar que se está interactuando con ellos. Si
usas MaterialTheme en tu jerarquía, se usa un Ripple como el
Indication predeterminado dentro de modificadores como clickable y
indication.
En la mayoría de los casos, puedes confiar en el objeto Ripple predeterminado. Si necesitas configurar su apariencia, puedes usar RippleTheme para cambiar propiedades, como el color y el alfa.
Puedes extender RippleTheme y usar las funciones de utilidad defaultRippleColor y defaultRippleAlpha. Luego, puedes proporcionar tu tema de ondas personalizado en tu jerarquía con LocalRippleTheme:
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
RippleConfigurationMás información
Para obtener más información sobre los temas de Material en Compose, consulta los siguientes recursos adicionales.
Codelabs
Videos
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Sistemas de diseño personalizado en Compose
- Cómo migrar de Material 2 a Material 3 en Compose
- Accesibilidad en Compose