Styles en Jetpack Compose: la mejora para estilizar componentes sin abusar de Modifier
La nueva API Style de Jetpack Compose propone una forma distinta de definir la apariencia de componentes. No se trata de crear una data class propia con colores y tamaños: es una API experimental integrada en Compose para agrupar propiedades visuales, aplicar variantes reutilizables y reaccionar a estados como pulsado, foco o hover. Su objetivo no es eliminar Modifier, sino reservarlo para aquello que hace mejor: comportamiento, semántica, gestos y layouts específicos. (Android Developers)
Qué son realmente los Style
Un Style define propiedades visuales como fondo, padding, bordes, forma, sombras, tamaño, transformaciones o atributos tipográficos. Puedes pasarlo a un componente que exponga un parámetro style o aplicarlo sobre layouts mediante Modifier.styleable. (Android Developers)
La diferencia clave es que un Style funciona como una capa de propiedades sobrescribibles. Si defines dos veces un fondo, se aplicará el último. Con los modifiers ocurre lo contrario: normalmente se encadenan de forma aditiva. Añadir dos bordes con Modifier.border() puede dibujar dos bordes; aplicar dos fondos en un Style reemplaza el anterior. (Android Developers)
Esto cambia cómo modelamos un design system. En lugar de construir una larga cadena de Modifier en cada pantalla, puedes definir un estilo base y reemplazar solamente las propiedades que cambian.
Style no reemplaza a Modifier
La forma correcta de entender la API es esta: Style es un tipo especializado de Modifier orientado a configuración visual. Todo lo que logra un Style puede conseguirse con modifiers, pero Style no cubre todas las capacidades de Modifier. (Android Developers)
| Necesidad | Opción recomendada |
|---|---|
| Fondo, borde, forma, padding, tamaño y tipografía | Style |
| Apariencia compartida por un tema o design system | Style |
| Animaciones visuales entre estados | Style |
| Clicks, gestos y comportamiento | Modifier |
| Semántica y accesibilidad | Modifier |
| Layouts puntuales o ajustes únicos | Modifier |
| Propiedades que deben acumularse | Modifier |
Un componente puede usar ambos sin problema: Modifier para hacerlo pulsable o colocarlo en pantalla, y Style para decidir cómo se ve.
Un ejemplo con estados y animación
El siguiente ejemplo aplica un Style a un Box. El Modifier.clickable conserva la responsabilidad de la interacción, mientras que Style define fondo, padding, forma y respuesta visual al estado pressed.
@Composable
fun SaveSurface(
onSave: () -> Unit,
modifier: Modifier = Modifier
) {
val interactionSource = remember { MutableInteractionSource() }
val styleState = remember(interactionSource) {
MutableStyleState(interactionSource)
}
val saveStyle = Style {
externalPadding(horizontal = 16.dp, vertical = 8.dp)
contentPadding(20.dp)
shape(RoundedCornerShape(20.dp))
background(Color(0xFF6750A4))
pressed {
animate {
background(Color(0xFF4F378B))
}
animate(
spring(
dampingRatio = Spring.DampingRatioMediumBouncy
)
) {
scale(0.98f)
}
}
}
Box(
modifier = modifier
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onSave
)
.styleable(styleState, saveStyle)
) {
Text("Guardar cambios")
}
}
Con modifiers tradicionales, este comportamiento suele implicar observar el estado de interacción, calcular valores con animateColorAsState o APIs similares y aplicar las animaciones manualmente. Los Style permiten declarar esas variaciones dentro del propio estilo mediante bloques como pressed, hovered o focused, además de incluir animate para interpolar propiedades visuales. (Android Developers)
Por qué supone una mejora
Estados visuales más declarativos
Un botón puede tener estilos distintos cuando está deshabilitado, seleccionado, enfocado o pulsado. Con StyleState, estas reglas viven en el mismo lugar que el resto de la apariencia, en lugar de dispersarse entre condiciones, animaciones y cadenas de modifiers. La API también admite estados personalizados, útiles para componentes de reproducción, carga, error o selección. (Android Developers)
Mejor encaje con el theming
Los styles pueden definirse como valores reutilizables y combinarse con then. Esto permite partir de una apariencia base y crear variantes sin duplicar toda la configuración. Además, pueden leer valores de CompositionLocal, una pieza importante para conectarlos con tokens de diseño globales. (Android Developers)
Animaciones visuales con menos recomposición
Según la documentación de Compose, los cambios de Style se resuelven en las fases de layout y dibujo, evitando la fase de composición en muchas actualizaciones visuales. Esto resulta especialmente interesante para animar color, escala, bordes o padding durante interacciones frecuentes. (Android Developers)
Cuándo usarlo en un proyecto real
Style encaja especialmente bien en componentes propios de un design system: tarjetas, botones internos, chips, superficies interactivas o controles que necesiten muchas variantes visuales. También es una buena opción cuando quieres reemplazar valores por defecto sin que las propiedades se acumulen de forma inesperada.
No conviene usarlo por inercia para cada Box o Text. Resolver un estilo completo puede tener más coste que aplicar un único modifier, y los modifiers siguen siendo imprescindibles para comportamiento y accesibilidad. (Android Developers)
La mejora no consiste en dejar de usar Modifier, sino en evitar que tenga que resolver todos los problemas de estilo. Usa Style para expresar identidad visual, variantes, estados y transiciones; usa Modifier para definir comportamiento y contexto. Esa separación hace que los componentes sean más coherentes, las APIs más pequeñas y el design system más fácil de mantener.