Material 3 Expressive es la siguiente evolución de Material Design. Incluye temas y componentes actualizados, y funciones de personalización, como el color dinámico.
Esta guía se centra en la migración de la biblioteca de Jetpack Wear Compose Material 2.5 (androidx.wear.compose) a la biblioteca de Jetpack Wear Compose Material 3 (androidx.wear.compose.material3) para apps.
Enfoques
Para migrar el código de tu app de M2.5 a M3, sigue el mismo enfoque que se describe en la guía de migración de Compose Material para teléfonos, en particular:
- No deberías usar M2.5 ni M3 en una sola app a largo plazo.
- Ya no deberías usar las bibliotecas de Horologist Composables, Compose Layout ni Compose Material. En su lugar, usa los componentes de M3.
- Adopta un enfoque por fases.
Dependencias
M3 tiene un paquete y una versión diferentes a M2.5:
M2.5
implementation("androidx.wear.compose:compose-material:1.4.0")
M3
implementation("androidx.wear.compose:compose-material3:1.8.0-alpha02")
Consulta las versiones más recientes de M3 en la página de versiones de Wear Compose.
La versión 1.8.0-alpha02 de la biblioteca de Wear Compose Foundation introdujo
algunos componentes nuevos diseñados para funcionar con los componentes de Material 3.
Del mismo modo, SwipeDismissableNavHost de la biblioteca de Wear Compose Navigation tiene una animación actualizada cuando se ejecuta en Wear OS 6 (nivel de API 36) o versiones posteriores. Cuando
actualices a la versión de Wear Compose Material 3, te sugerimos que también actualices las bibliotecas de Wear
Compose Foundation y Navigation:
implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha02")
implementation("androidx.wear.compose:compose-navigation:1.8.0-alpha02")
Tema
En M2.5 y M3, la función de componibilidad del tema se denomina MaterialTheme, pero los paquetes de importación y los parámetros difieren. En M3, se cambió el nombre del parámetro Colors por ColorScheme y se introdujo MotionScheme para implementar transiciones.
M2.5
import androidx.wear.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes,
content = content
)
M3
import androidx.wear.compose.material3.MaterialTheme // ... MaterialTheme( colorScheme = ColorScheme(), typography = Typography(), shapes = Shapes(), motionScheme = MotionScheme.standard(), content = { /*content here*/ } )
Color
El sistema de colores de M3 es significativamente diferente al de M2.5. La cantidad de parámetros de color aumentó, tienen nombres diferentes y se asignan de forma distinta a los componentes de M3. En Compose, esto se aplica a la clase Colors de M2.5, la clase ColorScheme de M3 y las funciones relacionadas:
M2.5
import androidx.wear.compose.material.Colors
val appColorScheme: Colors = Colors(
// M2.5 Color parameters
)
M3
import androidx.wear.compose.material3.ColorScheme // ... val appColorScheme: ColorScheme = ColorScheme( // M3 ColorScheme parameters )
En la siguiente tabla, se describen las diferencias clave entre M2.5 y M3:
| M2.5 | M3 |
|---|---|
Colors |
Se cambió el nombre a ColorScheme |
| 13 colores | 29 colores |
| N/A | Nuevo tema de color dinámico |
| N/A | Nuevos colores terciarios para una mayor expresión |
Temas de colores dinámicos
Una nueva función de M3 es la creación de temas de color dinámicos. Si los usuarios cambian los colores de la cara de reloj, los colores de la IU cambian para que coincidan.
Usa la función dynamicColorScheme para implementar el esquema de colores dinámico y proporciona un defaultColorScheme como resguardo en caso de que el esquema de colores dinámico no esté disponible.
@Composable fun myApp() { val dynamicColorScheme = dynamicColorScheme(LocalContext.current) MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {} } internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)
Tipografía
El sistema de tipografía en M3 es diferente al de M2.5 y, además, incluye las siguientes características:
- Nueve estilos de texto nuevos
- Fuentes flexibles, que permiten personalizar las escalas de tipos para diferentes grosores, anchos y redondeces
AnimatedText, que usa fuentes flexibles
M2.5
import androidx.wear.compose.material.Typography
val Typography = Typography(
// M2.5 TextStyle parameters
)
M3
import androidx.wear.compose.material3.Typography val Typography = Typography( // M3 TextStyle parameters )
Fuentes flexibles
Las fuentes flexibles permiten que los diseñadores especifiquen el ancho y el grosor de los tipos para tamaños específicos.
Estilos de texto
Los siguientes TextStyles están disponibles en M3. Varios componentes de M3 los emplean de forma predeterminada.
| Tipografía | TextStyle |
|---|---|
| Pantalla | displayLarge, displayMedium, displaySmall |
| Título | titleLarge, titleMedium, titleSmall |
| Etiqueta | labelLarge, labelMedium, labelSmall |
| Cuerpo | bodyLarge, bodyMedium, bodySmall, bodyExtraSmall |
| Numeral | numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall |
| Arco | arcLarge, arcMedium, arcSmall |
Forma
El sistema de formas en M3 es diferente al de M2.5. La cantidad de parámetros de forma aumentó, tienen nombres diferentes y se asignan, de forma distinta, a los componentes de M3. Están disponibles los siguientes tamaños de formas:
- Extrapequeño
- Pequeño
- Mediano
- Grande
- Extragrande
En Compose, esto se aplica a la clase Shapes de M2.5 y la clase Shapes de M3:
M2.5
import androidx.wear.compose.material.Shapes
val Shapes = Shapes(
// M2.5 Shapes parameters
)
M3
import androidx.wear.compose.material3.Shapes val Shapes = Shapes( // M3 Shapes parameters )
Usa la asignación de parámetros de Shapes de Cómo migrar de Material 2 a Material 3 en Compose como punto de partida.
Transformación de formas
M3 presenta la transformación de formas: ahora las formas se transforman en respuesta a las interacciones.
El comportamiento de Shape Morphing está disponible como una variación en varios botones redondos. Consulta la siguiente lista de botones que admiten Shape Morphing:
| Botones | Función de transformación de formas |
|---|---|
IconButton |
IconButtonDefaults.animatedShapes anima el botón de ícono cuando se presiona. |
IconToggleButton |
IconToggleButtonDefaults.animatedShapes anima el botón de activación de ícono cuando se presiona y IconToggleButtonDefaults.variantAnimatedShapes anima el botón de activación de ícono cuando se presiona y se marca o desmarca |
TextButton |
TextButtonDefaults.animatedShapes anima el botón de texto cuando se presiona |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes anima el botón de activación de texto cuando se presiona, y TextToggleButtonDefaults.variantAnimatedShapes anima el botón de activación de texto cuando se presiona y se marca o desmarca. |
Componentes y diseño
La mayoría de los componentes y diseños de M2.5 están disponibles en M3. Sin embargo, algunos componentes y diseños de M3 no existían en M2.5. Además, algunos componentes de M3 tienen más variaciones que sus equivalentes en M2.5.
Si bien algunos componentes requieren consideraciones especiales, se recomiendan las siguientes asignaciones de funciones como punto de partida:
A continuación, se muestra una lista de los componentes comunes de Material 3 y sus equivalentes de Material 2.5:
Por último, se incluye una lista de algunos componentes relevantes de la biblioteca de Wear Compose Foundation:
| Wear Compose Foundation 1.8.0-alpha02 | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | Se usa para anotar elementos componibles en una aplicación, para hacer un seguimiento de la parte activa de la composición y coordinar el enfoque. |
| androidx.wear.compose.foundation.pager.HorizontalPager | Es un buscapersonas de desplazamiento horizontal, creado sobre los componentes de Compose Foundation con mejoras específicas para Wear que mejoran el rendimiento y el cumplimiento de los lineamientos de Wear OS. |
| androidx.wear.compose.foundation.pager.VerticalPager | Es un buscapersonas con desplazamiento vertical, creado sobre los componentes de Compose Foundation con mejoras específicas para Wear que mejoran el rendimiento y el cumplimiento de los lineamientos de Wear OS. |
| androidx.wear.compose.foundation.lazy.TransformingLazyColumn | Se puede usar en lugar de ScalingLazyColumn para agregar efectos de transformación de desplazamiento a cada elemento. |
Botones
Los botones de M3 son diferentes de los de M2.5. El chip de M2.5 se reemplazó por Button. La implementación de Button proporciona valores predeterminados para Text,
maxLines y textAlign. Esos valores predeterminados se pueden anular en el elemento Text.
M2.5
import androidx.wear.compose.material.Chip
//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)
M3
//M3 Buttons Button(onClick = { }){} CompactButton(onClick = { }){} IconButton(onClick = { }){} TextButton(onClick = { }){}
M3 también incluye nuevas variaciones de botones. Consulta la descripción general de la referencia de la API de Compose Material 3.
M3 presenta un nuevo botón: EdgeButton. Los EdgeButton están disponibles en 4
tamaños diferentes: extrapequeño, pequeño, mediano y grande. La implementación de EdgeButton proporciona un valor predeterminado para maxLines según el tamaño, que se puede personalizar.
Si usas TransformingLazyColumn o ScalingLazyColumn, pasa el EdgeButton al ScreenScaffold para que se transforme y cambie de forma con el desplazamiento, en lugar de agregar un EdgeButton como el elemento final de la lista. Consulta
el siguiente código para ver cómo usar EdgeButton con ScreenScaffold y
TransformingLazyColumn.
val state = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = state, edgeButton = { EdgeButton( onClick = { }, modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text(stringResource(R.string.show)) } }, ) { contentPadding -> TransformingLazyColumn(state = state, contentPadding = contentPadding) { // additional code here // ... } }
Scaffold
El andamiaje en M3 es diferente al de M2.5. En M3, AppScaffold y el nuevo elemento componible ScreenScaffold reemplazaron a Scaffold. AppScaffold y ScreenScaffold diseñan la estructura de una pantalla y coordinan las transiciones de los componentes ScrollIndicator y TimeText.
AppScaffold permite que los elementos de pantalla estáticos, como TimeText, permanezcan visibles durante las transiciones en la app, como el deslizamiento para descartar. Proporciona una ranura para el contenido principal de la aplicación, que, por lo general, proporcionará un componente de navegación, como SwipeDismissableNavHost.
Declaras un AppScaffold para la actividad y usas un ScreenScaffold para cada pantalla.
AppScaffold agrega un componente TimeText predeterminado a las pantallas. Puedes
anularlo si quieres personalizarlo con el parámetro timeText.
M2.5
import androidx.wear.compose.material.Scaffold
Scaffold {...}
M3
AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { composable("message_list") { MessageList(onMessageClick = { id -> navController.navigate("message_detail/$id") }) } composable("message_detail/{id}") { MessageDetail(id = it.arguments?.getString("id")!!) } } } } // Implementation of one of the screens in the navigation @Composable fun MessageDetail(id: String) { // .. Screen level content goes here val scrollState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = scrollState, ) { contentPadding -> // Screen content goes here // ...
Si usas un HorizontalPager con HorizontalPageIndicator, puedes
migrar a HorizontalPagerScaffold. HorizontalPagerScaffold se coloca dentro de un AppScaffold. AppScaffold y HorizontalPagerScaffold diseñan la estructura de un Pager y coordinan las transiciones de los componentes HorizontalPageIndicator y TimeText.
HorizontalPagerScaffold muestra el HorizontalPageIndicator en el centro de la pantalla de forma predeterminada y las coordenadas que muestran o bien ocultan TimeText y HorizontalPageIndicator según si se está paginando el Pager, lo que determina el PagerState.
También hay un nuevo componente AnimatedPage, que anima una página dentro de un Pager con un efecto de escalamiento y scrim según su posición.
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( ListHeaderDefaults.minimumTopListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(text = "Pager sample") } } item { Card( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { if (page == 0) { Text(text = "Page #$page. Swipe right") } else { Text(text = "Page #$page. Swipe left and right") } } } } } } } } }
Por último, M3 presenta un VerticalPagerScaffold que sigue el mismo patrón que HorizontalPagerScaffold:
@Composable fun VerticalPagerScaffoldSample() { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } } }
Marcador de posición
Hay algunos cambios en la API entre M2.5 y M3. M3 proporciona dos modificadores de marcador de posición:
Modifier.placeholder, que se dibuja en lugar del contenido que aún no se cargó- Un efecto de brillo de marcador de posición
Modifier.placeholderShimmerque proporciona un efecto de brillo de marcador de posición que se ejecuta en un bucle de animación mientras se espera que se carguen los datos.
Consulta la siguiente tabla para ver los cambios adicionales en el componente Placeholder.
| M2.5 | M3 |
|---|---|
PlaceholderState.startPlaceholderAnimation |
Se quitó |
PlaceholderState.placeholderProgression |
Se quitó |
PlaceholderState.isShowContent |
Se reemplazó por PlaceholderState.isVisible (booleano invertido) |
PlaceholderState.isWipeOff |
Se quitó |
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush |
Se quitó |
PlaceholderDefaults.placeholderBackgroundBrush |
Se quitó |
PlaceholderDefaults.placeholderChipColors |
Se quitó |
SwipeDismissableNavHost
SwipeDismissableNavHost forma parte de wear.compose.navigation. Cuando este componente se usa con M3, el MaterialTheme de M3 actualiza LocalSwipeToDismissBackgroundScrimColor y LocalSwipeToDismissContentScrimColor.
TransformingLazyColumn
TransformingLazyColumn forma parte de androidx.wear.compose.foundation.lazy y agrega compatibilidad con animaciones de escalamiento y transformación en elementos de lista durante el desplazamiento, lo que mejora la experiencia del usuario. Se recomienda que las apps migren de ScalingLazyColumn a TransformingLazyColumn.
Al igual que ScalingLazyColumn, proporciona rememberTransformingLazyColumnState() para crear un TransformingLazyColumnState que se recuerda en todas las composiciones.
Para agregar animaciones de escalamiento y transformación, agrega lo siguiente a cada elemento de la lista:
Modifier.transformedHeight, que te permite calcular la altura transformada de los elementos con unTransformationSpec, puedes usarrememberTransformationSpec(), a menos que necesites más personalización.- A
SurfaceTransformation
Para verificar que el padding sea correcto en la parte superior e inferior de la lista, usa el modificador minimumVerticalContentPadding.
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
Vínculos útiles
Para obtener más información sobre la migración de M2.5 a M3 en Compose, consulta los siguientes recursos adicionales.