Migrar do Material 2.5 para o Material 3 no Compose para Wear OS

O Material 3 Expressive (link em inglês) é a próxima evolução do Material Design. Ele inclui temas, componentes e recursos de personalização atualizados, como cores dinâmicas.

Este guia se concentra na migração da biblioteca Jetpack Wear Compose Material 2.5 (androidx.wear.compose) para a biblioteca Jetpack Wear Compose Material 3 (androidx.wear.compose.material3) para apps.

Abordagens

Para migrar o código do app do M2.5 para o M3, siga a mesma abordagem descrita no Guia de migração do Material do Compose para smartphones, em especial:

Dependências

O M3 tem um pacote e uma versão separados para o M2.5:

M2.5

implementation("androidx.wear.compose:compose-material:1.4.0")

M3

implementation("androidx.wear.compose:compose-material3:1.6.0")

Consulte as versões mais recentes do M3 na página de versões do Wear Compose Material 3.

A biblioteca Wear Compose Foundation versão 1.6.0 introduziu alguns novos componentes projetados para funcionar com componentes do Material 3. Da mesma forma, o SwipeDismissableNavHost da biblioteca Wear Compose Navigation tem uma animação atualizada ao ser executado no Wear OS 6 (nível 36 da API) ou mais recente. Ao atualizar para a versão do Wear Compose Material 3, sugerimos que você também atualize as bibliotecas Wear Compose Foundation e Navigation:

implementation("androidx.wear.compose:compose-foundation:1.6.0")
implementation("androidx.wear.compose:compose-navigation:1.6.0")

Tema

Nas versões M2.5 e M3, o tema combinável é chamado de MaterialTheme, mas os pacotes e parâmetros de importação são diferentes. No M3, o parâmetro Colors foi renomeado para ColorScheme, e o MotionScheme foi introduzido para implementar transições.

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*/ }
    )

Cor

O sistema de cores no M3 é significativamente diferente do M2.5. O número de parâmetros de cor aumentou, eles têm nomes diferentes e são mapeados de forma diferente para os componentes do M3. No Compose, isso se aplica à classe Colors do M2.5, à classe ColorScheme do M3 e às funções 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
    )

A tabela a seguir descreve as principais diferenças entre M2.5 e M3:

M2.5 M3
Color Foi renomeado como ColorScheme
13 cores 28 cores
N/A Novo tema de cores dinâmicas
N/A Novas cores terciárias para mais expressão

Temas de cores dinâmicas

Um novo recurso do M3 é a tematização de cores dinâmicas (link em inglês). Se os usuários mudarem as cores do mostrador do relógio, as cores na interface vão mudar para corresponder.

Use a função dynamicColorScheme para implementar o esquema de cores dinâmicas e forneça um defaultColorScheme como substituto caso o esquema de cores dinâmicas não esteja disponível.

@Composable
fun myApp() {
    val dynamicColorScheme = dynamicColorScheme(LocalContext.current)
    MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {}
}

internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)

Tipografia

O sistema de tipografia (link em inglês) no M3 é diferente do M2.5 e inclui os seguintes recursos:

  • Nove novos estilos de texto
  • Fontes flexíveis, que permitem a personalização das escalas tipográficas para diferentes pesos, larguras e arredondamentos
  • AnimatedText, que usa fontes flexíveis

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
)

Fontes flexíveis

Com as fontes flexíveis, os designers podem especificar a largura e o peso do tipo para tamanhos específicos.

Estilos de texto

Os seguintes TextStyles estão disponíveis no M3. Eles são usados por padrão por vários componentes do M3.

Tipografia TextStyle
Tela displayLarge, displayMedium, displaySmall
Título titleLarge, titleMedium, titleSmall
Rótulo labelLarge, labelMedium, labelSmall
Corpo bodyLarge, bodyMedium, bodySmall, bodyExtraSmall
Numeral numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall
Arco arcLarge, arcMedium, arcSmall

Forma

O sistema de formas (link em inglês) no M3 é diferente do M2.5. O número de parâmetros de forma aumentou, eles são nomeados de forma diferente e são mapeados de forma diferente para os componentes do M3. Os seguintes tamanhos de forma estão disponíveis:

  • Extrapequena
  • Pequenas
  • Médio
  • Grande
  • Extragrande

No Compose, isso se aplica às classes Shapes do M2 e Shapes do 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
)

Use o mapeamento de parâmetros de formas em Migrar do Material 2 para o Material 3 no Compose como ponto de partida.

Transformação de forma

O M3 apresenta a transformação de formas: agora elas se transformam em resposta às interações.

O comportamento de transformação de forma está disponível como uma variação em vários botões circulares. Consulte a lista a seguir de botões que oferecem suporte a essa transformação:

Botões Função de transformação de forma
IconButton IconButtonDefaults.animatedShape anima o botão de ícone ao pressionar
IconToggleButton IconToggleButtonDefaults.animatedShape anima o botão de alternância de ícone ao pressionar, e
IconToggleButtonDefaults.variantAnimatedShapes anima o botão de alternância de ícone ao pressionar e marcar/desmarcar.
TextButton TextButtonDefaults.animatedShape anima o botão de texto ao pressionar.
TextToggleButton TextToggleButtonDefaults.animatedShapes anima a alternância de texto ao pressionar, e TextToggleButtonDefaults.variantAnimatedShapes anima a alternância de texto ao pressionar e marcar/desmarcar.

Componentes e layout

A maioria dos componentes e layouts do M2.5 está disponível no M3. No entanto, alguns componentes e layouts do M3 não existiam no M2.5. Além disso, alguns componentes do M3 têm mais variações do que os equivalentes no M2.5.

Embora alguns componentes exijam considerações especiais, os mapeamentos de funções abaixo são recomendados como ponto de partida:

Material 2.5 Material 3
androidx.wear.compose.material.dialog.Alert androidx.wear.compose.material3.AlertDialog
androidx.wear.compose.material.Button androidx.wear.compose.material3.IconButton ou androidx.wear.compose.material3.TextButton
androidx.wear.compose.material.Card androidx.wear.compose.material3.Card
androidx.wear.compose.material.TitleCard androidx.wear.compose.material3.TitleCard
androidx.wear.compose.material.AppCard androidx.wear.compose.material3.AppCard
androidx.wear.compose.material.Checkbox Sem equivalente do M3, migre para androidx.wear.compose.material3.CheckboxButton ou androidx.wear.compose.material3.SplitCheckboxButton
androidx.wear.compose.material.Chip androidx.wear.compose.material3.Button ou
androidx.wear.compose.material3.OutlinedButton ou
androidx.wear.compose.material3.FilledTonalButton ou
androidx.wear.compose.material3.ChildButton
androidx.wear.compose.material.CompactChip androidx.wear.compose.material3.CompactButton
androidx.wear.compose.material.InlineSlider androidx.wear.compose.material3.Slider
androidx.wear.compose.material.LocalContentAlpha() Foi removido porque não é usado por Text ou Icon no Material 3
androidx.wear.compose.material.PositionIndicator androidx.wear.compose.material3.ScrollIndicator
androidx.wear.compose.material.RadioButton Sem equivalente do M3, migre para androidx.wear.compose.material3.RadioButton ou androidx.wear.compose.material3.SplitRadioButton
androidx.wear.compose.material.SwipeToRevealCard androidx.wear.compose.material3.SwipeToReveal
androidx.wear.compose.material.SwipeToRevealChip androidx.wear.compose.material3.SwipeToReveal
android.wear.compose.material.Scaffold androidx.wear.compose.material3.AppScaffold e androidx.wear.compose.material3.ScreenScaffold
androidx.wear.compose.material.SplitToggleChip Não há equivalente no M3. Migre para androidx.wear.compose.material3.SplitCheckboxButton, androidx.wear.compose.material3.SplitSwitchButton ou androidx.wear.compose.material3.SplitRadioButton.
androidx.wear.compose.material.Switch Não há equivalente no M3. Migre para androidx.wear.compose.material3.SwitchButton ou androidx.wear.compose.material3.SplitSwitchButton.
androidx.wear.compose.material.ToggleButton androidx.wear.compose.material3.IconToggleButton ou androidx.wear.compose.material3.TextToggleButton
androidx.wear.compose.material.ToggleChip androidx.wear.compose.material3.CheckboxButton ou
androidx.wear.compose.material3.RadioButton ou
androidx.wear.compose.material3.SwitchButton
androidx.wear.compose.material.Vignette Removido porque não está incluído no design do Material 3 Expressive para Wear OS

Confira uma lista completa de todos os componentes do Material 3:

Material 3 Componente equivalente do Material 2.5 (se não for novo no M3)
androidx.wear.compose.material3.AlertDialog androidx.wear.compose.material.dialog.Alert
androidx.wear.compose.material3.AnimatedPage Novo
androidx.wear.compose.material3.AnimatedText Novo
androidx.wear.compose.material3.AppScaffold android.wear.compose.material.Scaffold (com androidx.wear.compose.material3.ScreenScaffold)
androidx.wear.compose.material3.Button androidx.wear.compose.material.Chip
androidx.wear.compose.material3.ButtonGroup Novo
androidx.wear.compose.material3.Card androidx.wear.compose.material.Card
androidx.wear.compose.material3.CheckboxButton androidx.wear.compose.material.ToggleChip com um controle de alternância de caixa de seleção
androidx.wear.compose.material3.ChildButton androidx.wear.compose.material.Chip (somente quando não é necessário um plano de fundo)
androidx.wear.compose.material3.CircularProgressIndicator androidx.wear.compose.material.CircularProgressIndicator
androidx.wear.compose.material3.CompactButton androidx.wear.compose.material.CompactChip
androidx.wear.compose.material3.ConfirmationDialog androidx.wear.compose.material.dialog.Confirmation
androidx.wear.compose.material3.curvedText androidx.wear.compose.material.curvedText
androidx.wear.compose.material3.DatePicker Novo
androidx.wear.compose.material3.Dialog androidx.wear.compose.material.dialog.Dialog
androidx.wear.compose.material3.EdgeButton Novo
androidx.wear.compose.material3.FadingExpandingLabel Novo
androidx.wear.compose.material3.FilledTonalButton androidx.wear.compose.material.Chip quando um plano de fundo de botão tonal é necessário
androidx.wear.compose.material3.HorizontalPageIndicator androidx.wear.compose.material.HorizontalPageIndicator
androidx.wear.compose.material3.HorizontalPagerScaffold Novo
androidx.wear.compose.material3.Icon androidx.wear.compose.material.Icon
androidx.wear.compose.material3.IconButton androidx.wear.compose.material.Button
androidx.wear.compose.material3.IconToggleButton androidx.wear.compose.material.ToggleButton
androidx.wear.compose.material3.LevelIndicator Novo
androidx.wear.compose.material3.LinearProgressIndicator Novo
androidx.wear.compose.material3.ListHeader androidx.wear.compose.material.ListHeader
androidx.wear.compose.material3.ListSubHeader Novo
androidx.wear.compose.material3.MaterialTheme androidx.wear.compose.material.MaterialTheme
androidx.wear.compose.material3.OpenOnPhoneDialog Novo
androidx.wear.compose.material3.Picker androidx.wear.compose.material.Picker
androidx.wear.compose.material3.PickerGroup androidx.wear.compose.material.PickerGroup
androidx.wear.compose.material3.RadioButton androidx.wear.compose.material.ToggleChip com um controle de alternância de botão de opção
androidx.wear.compose.material3.ScreenScaffold android.wear.compose.material.Scaffold (com androidx.wear.compose.material3.AppScaffold)
androidx.wear.compose.material3.ScrollIndicator androidx.wear.compose.material.PositionIndicator
androidx.wear.compose.material3.scrollAway androidx.wear.compose.material.scrollAway
androidx.wear.compose.material3.SegmentedCircularProgressIndicator Novo
androidx.wear.compose.material3.Slider androidx.wear.compose.material.InlineSlider
androidx.wear.compose.material3.SplitRadioButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.SplitCheckboxButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.SplitSwitchButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.Stepper androidx.wear.compose.material.Stepper
androidx.wear.compose.material3.SwipeToDismissBox androidx.wear.compose.material.SwipeToDismissBox
androidx.wear.compose.material3.SwipeToReveal androidx.wear.compose.material.SwipeToRevealCard e androidx.wear.compose.material.SwipeToRevealChip
androidx.wear.compose.material3.SwitchButton androidx.wear.compose.material.ToggleChip com um controle de ativação/desativação
androidx.wear.compose.material3.Text androidx.wear.compose.material.Text
androidx.wear.compose.material3.TextButton androidx.wear.compose.material.Button
androidx.wear.compose.material3.TextToggleButton androidx.wear.compose.material.ToggleButton
androidx.wear.compose.material3.TimeText androidx.wear.compose.material.TimeText
androidx.wear.compose.material3.VerticalPagerScaffold Novo

Por fim, uma lista de alguns componentes relevantes da biblioteca Wear Compose Foundation:

Wear Compose Foundation 1.6.0
androidx.wear.compose.foundation.hierarchicalFocusGroup Usada para anotar elementos combináveis em um aplicativo, acompanhar a parte ativa da composição e coordenar o foco.
androidx.wear.compose.foundation.pager.HorizontalPager Um pager de rolagem horizontal, criado com base nos componentes do Compose Foundation e melhorias específicas do Wear para melhorar o desempenho e a conformidade com as diretrizes do Wear OS.
androidx.wear.compose.foundation.pager.VerticalPager Um pager de rolagem vertical, criado com base nos componentes do Compose Foundation e com melhorias específicas do Wear para melhorar o desempenho e a conformidade com as diretrizes do Wear OS.
androidx.wear.compose.foundation.lazy.TransformingLazyColumn Pode ser usado em vez de ScalingLazyColumn para adicionar efeitos de transformação de rolagem a cada item.

Botões

Os botões no M3 são diferentes do M2.5. O ícone M2.5 foi substituído por Button. A implementação Button oferece valores padrão para Text maxLines e textAlign. Esses valores padrão podem ser substituídos no 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 = { }){}

O M3 também inclui novas variações de botões. Confira na Visão geral da referência da API Compose Material 3.

O M3 apresenta um novo botão: EdgeButton. O EdgeButton está disponível em quatro tamanhos diferentes: extrapequeno, pequeno, médio e grande. A implementação EdgeButton fornece um valor padrão para maxLines dependendo do tamanho, que pode ser personalizado.

Se você estiver usando TransformingLazyColumn ou ScalingLazyColumn, transmita o EdgeButton para o ScreenScaffold para que ele se transforme, mudando de forma com a rolagem, em vez de adicionar um EdgeButton como o último item da lista. Confira o código a seguir para verificar como usar EdgeButton com ScreenScaffold e TransformingLazyColumn.

val state = rememberTransformingLazyColumnState()
ScreenScaffold(
    scrollState = state,
    contentPadding =
        rememberResponsiveColumnPadding(
            first = ColumnItemType.ListHeader
        ),
    edgeButton = {
        EdgeButton(
            onClick = { }
        ) {
            Text(stringResource(R.string.show))
        }
    }
){ contentPadding ->
    TransformingLazyColumn(state = state, contentPadding = contentPadding,){
        // additional code here
    }
}

Scaffold

O Scaffold no M3 é diferente do M2.5. No M3, AppScaffold e o novo elemento combinável ScreenScaffold substituíram o Scaffold. AppScaffold e ScreenScaffold definem o layout da estrutura de uma tela e coordenam as transições dos componentes ScrollIndicator e TimeText.

O AppScaffold permite que elementos estáticos da tela, como TimeText, fiquem visíveis durante transições no app, como o gesto de deslizar para fechar. ​​Ele fornece um slot para o conteúdo principal do aplicativo, que geralmente é fornecido por um componente de navegação, como SwipeDismissableNavHost

Você declara um AppScaffold para a Activity e usa um ScreenScaffold para cada tela. O AppScaffold adiciona um TimeTextcomponent padrão às telas. É possível substituir isso se quiser personalizar usando o 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 padding = rememberResponsiveColumnPadding(
        first = ColumnItemType.BodyText
    )

    ScreenScaffold(
        scrollState = scrollState,
        contentPadding = padding
    ) { scaffoldPaddingValues ->
        // Screen content goes here
        // ...

Se você estiver usando um HorizontalPager com HorizontalPagerIndicator, poderá migrar para HorizontalPagerScaffold. O HorizontalPagerScaffold é colocado em um AppScaffold. AppScaffold e HorizontalPagerScaffold definem o layout da estrutura de um Pager e coordenam as transições dos componentes HorizontalPageIndicator e TimeText.

O HorizontalPagerScaffold mostra o HorizontalPageIndicator no centro da tela por padrão e coordena a exibição e ocultação de TimeText e HorizontalPageIndicator de acordo com o Pager. Isso é determinado pelo PagerState.

Há também um novo componente AnimatedPage, que anima uma página em um Pager com um efeito de escalonamento e tela escura com base na posição dela.

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })
    val columnState = rememberTransformingLazyColumnState()
    val contentPadding = rememberResponsiveColumnPadding(
        first = ColumnItemType.ListHeader,
        last = ColumnItemType.BodyText,
    )
    HorizontalPagerScaffold(pagerState = pagerState) {
        HorizontalPager(
            state = pagerState,
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold(
                    scrollState = columnState,
                    contentPadding = contentPadding
                ) { contentPadding ->
                    TransformingLazyColumn(
                        state = columnState,
                        contentPadding = contentPadding
                    ) {
                        item {
                            ListHeader(
                                modifier = Modifier.fillMaxWidth()
                            ) {
                                Text(text = "Pager sample")
                            }
                        }
                        item {
                            if (page == 0) {
                                Text(text = "Page #$page. Swipe right")
                            }
                            else{
                                Text(text = "Page #$page. Swipe left and right")
                            }
                        }
                    }
                }

            }
        }
    }
}

Por fim, o M3 apresenta um VerticalPagerScaffold que segue o mesmo padrão do HorizontalPagerScaffold:

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })

    VerticalPagerScaffold(pagerState = pagerState) {
        VerticalPager(
            state = pagerState
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold {
                    ///…
                }
            }
        }
    }
}

Marcador de posição

Há algumas mudanças na API entre o M2.5 e o M3. O Placeholder.PlaceholderDefaults agora oferece dois modificadores:

  • Modifier.placeholder, que é desenhado em vez de conteúdo que ainda não foi carregado.
  • Um efeito de brilho de marcador de posição Modifier.placeholderShimmer que fornece um efeito de brilho de marcador de posição que é executado em um loop de animação enquanto aguarda o carregamento dos dados.

Confira na tabela a seguir outras mudanças no componente Placeholder.

M2.5 M3
PlaceholderState.startPlaceholderAnimation Foi removida
PlaceholderState.placeholderProgression Foi removida
PlaceholderState.isShowContent Foi renomeado como !PlaceholderState.isVisible
PlaceholderState.isWipeOff Foi removida
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush Foi removida
PlaceholderDefaults.placeholderBackgroundBrush Foi removida
PlaceholderDefaults.placeholderChipColors Foi removida

SwipeDismissableNavHost

SwipeDismissableNavHost faz parte de wear.compose.navigation. Quando esse componente é usado com o M3, o MaterialTheme do M3 atualiza o LocalSwipeToDismissBackgroundScrimColor e o LocalSwipeToDismissContentScrimColor.

TransformingLazyColumn

O TransformingLazyColumn faz parte do wear.compose.lazy.foundation e adiciona suporte para animações de escalonamento e transformação em itens de lista durante a rolagem, melhorando a experiência do usuário. É altamente recomendável que os apps migrem de ScalingLazyColumn para TransformingLazyColumn

Assim como ScalingLazyColumn, ele fornece rememberTransformingLazyColumnState() para criar um TransformingLazyColumnState que é lembrado em todas as composições.

Para adicionar animações de escalonamento e transformação, adicione o seguinte a cada item da lista:

  • Modifier.transformedHeight, que permite calcular a altura transformada dos itens usando um TransformationSpec, é possível usar rememberTransformationSpec(), a menos que você precise de mais personalização.
  • Um SurfaceTransformation

Para verificar se o padding está correto na parte de cima e de baixo da lista, use o 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,
                )
            }
        }
    }
}

Para saber mais sobre a migração do M2.5 para o M3 no Compose, consulte os recursos abaixo.

Amostras

Referência da API e código-fonte

Design