Como criar transições incríveis com os movimentos do Material Design para Android

1. Introdução

O Material Design é um sistema para criar produtos digitais bonitos e arrojados. Ao combinar estilo, branding, interação e movimento em um conjunto consistente de princípios e componentes, as equipes de produto podem atingir o maior potencial de design.

logo_components_color_2x_web_96dp.png

Os componentes do Material Design (MDC, na sigla em inglês) ajudam os desenvolvedores a implementar o Material Design. Criados por uma equipe de engenheiros e designers de UX do Google, os MDC apresentam dezenas de componentes de interface bonitos e funcionais e estão disponíveis para Android, iOS, Web e Flutter.material.io/develop

O que é o sistema de movimento do Material Design para Android?

O sistema de movimento do Material Design para Android é um conjunto de padrões de transição na biblioteca MDC-Android que pode ajudar os usuários a entender e navegar em um app, conforme descrito nas diretrizes do Material Design.

Veja os quatro padrões principais de transição do Material Design:

  • Transformação de contêiner: faz a transição entre elementos da interface que incluem um contêiner. Cria uma conexão visível entre dois elementos ao transformar um no outro.
  • Eixo compartilhado: faz a transição entre elementos da interface que têm uma relação espacial ou de navegação. Usa uma transformação compartilhada nos eixos x, y ou z para reforçar a relação entre os elementos.
  • Esmaecimento cruzado: faz a transição entre elementos da interface que não têm uma relação forte entre si. Usa o esmaecimento e a exibição gradual de forma sequencial com uma escala do elemento de entrada.
  • Esmaecimento: usado para elementos da interface que entram ou saem dos limites da tela.

A biblioteca MDC-Android oferece classes de transição para esses padrões, criadas com base na biblioteca AndroidX Transition (androidx.transition) e no Android Transition Framework (android.transition):

AndroidX

  • Disponível no pacote com.google.android.material.transition
  • Oferece suporte ao nível 14 da API ou mais recente
  • Oferece suporte a fragmentos e visualizações, mas não a atividades ou janelas.
  • Contém correções de bugs com backport e comportamento consistente em todos os níveis de API

Framework

  • Disponível no pacote com.google.android.material.transition.platform
  • Oferece suporte ao nível 21 da API ou mais recente
  • Suporte a fragmentos, visualizações, atividades e janelas
  • Correções de bugs sem backport e podem ter um comportamento diferente dependendo do nível da API.

Neste codelab, você vai usar as transições do Material Design criadas com base na biblioteca AndroidX, ou seja, você vai se concentrar principalmente em fragmentos e visualizações.

O que você vai criar

Este codelab vai orientar você na criação de algumas transições em um app de e-mails de exemplo do Android chamado Reply, usando Kotlin, para demonstrar como usar transições da biblioteca MDC-Android para personalizar a aparência e o uso do app.

Você receberá o código inicial do app Reply para incorporar nele as seguintes transições do Material Design, que podem ser vistas no GIF do codelab completo abaixo:

  • Transição de transformação de contêiner da lista de e-mails para a página de detalhes
  • Transição de transformação de contêiner do FAB para a página "Escrever e-mail"
  • Transição de eixo z compartilhado do ícone de pesquisa para a página de visualização de pesquisa
  • Transição de esmaecimento cruzado entre as páginas da caixa de e-mails
  • Transição de transformação de contêiner do ícone de endereço de e-mail para a visualização de card

O domínio do iframe solicitado (youtu.be) não foi incluído na lista de permissões.

O que é necessário

  • Conhecimento básico de desenvolvimento para Android e Kotlin.
  • Android Studio (faça o download dele aqui, caso ainda não tenha feito)
  • Um dispositivo ou emulador Android (disponível no Android Studio)
  • O exemplo de código (confira a próxima etapa)

Qual é seu nível de experiência na criação de apps Android?

Iniciante Intermediário Proficiente

2. Configurar o ambiente de desenvolvimento

Iniciar o Android Studio

Ao abrir o Android Studio, você verá uma janela com o título "Welcome to Android Studio". No entanto, se você estiver iniciando essa ferramenta pela primeira vez, siga as etapas do assistente de configuração do Android Studio com os valores padrão. O sistema pode demorar vários minutos para fazer o download e instalar os arquivos necessários, então você pode deixar o programa em execução em segundo plano enquanto acompanha a próxima seção.

Opção 1: clonar o app inicial do codelab no GitHub

Para clonar este codelab no GitHub, execute estes comandos:

git clone https://github.com/material-components/material-components-android-motion-codelab.git
cd material-components-android-motion-codelab

Opção 2: fazer o download do arquivo ZIP do app inicial do codelab

O app inicial está localizado no diretório material-components-android-motion-codelab-develop.

Carregar o código inicial no Android Studio

  1. Quando o assistente de configuração for concluído e a janela Welcome to Android Studio for exibida, clique em Open an existing Android Studio project.

e3f200327a67a53.png

  1. Acesse o diretório em que você instalou o exemplo de código e selecione o exemplo de diretório para abrir o projeto.
  2. Aguarde um pouco enquanto o Android Studio cria e sincroniza o projeto, conforme mostrado nos indicadores de atividade na parte inferior da janela.
  1. Como o SDK do Android ou as ferramentas de compilação não estão presentes, o Android Studio poderá encontrar alguns erros de compilação. Veja um exemplo a seguir. Siga as instruções no Android Studio para instalar/atualizar essas ferramentas e sincronizar o projeto. Se os problemas persistirem, siga o guia sobre como atualizar suas ferramentas com o SDK Manager.

6e026ae171f5b1eb.png

Verificar as dependências do projeto

O projeto precisa de uma dependência na biblioteca MDC-Android. Provavelmente, o exemplo de código transferido por download já tem essa dependência listada, mas vamos conferir isso na configuração.

Navegue até o arquivo build.gradle do módulo app e confira se o bloco dependencies inclui uma dependência do MDC-Android:

implementation 'com.google.android.material:material:1.2.0'

Executar o app inicial

  1. Confira se a configuração do build à esquerda da opção de dispositivo é app.
  2. Pressione o botão verde Run / Play para criar e executar o app.

24218d0a6ae25803.png

  1. Se você já tiver um dispositivo Android listado entre os dispositivos disponíveis na janela Select Deployment Target, pule para a Etapa 8. Caso contrário, clique em Create New Virtual Device.
  2. Na tela Select Hardware, selecione um smartphone, como o Pixel 3, e clique em Next.
  3. Na tela System Image, selecione uma versão recente do Android, de preferência o nível da API mais alto. Se ele não estiver instalado, clique no link Download exibido e faça o download.
  4. Clique em Next.
  5. Na tela Android Virtual Device (AVD), mantenha as configurações como estão e clique em Finish.
  6. Selecione um dispositivo Android na caixa de diálogo de destino da implantação.
  7. Clique em OK.
  8. O Android Studio cria o app, faz a implantação e o abre automaticamente no dispositivo de destino.

Pronto. O código inicial da página inicial do Reply será executado no emulador. Você vai acessar a Caixa de entrada com uma lista de e-mails.

cc73eb0d0f779035.png

Opcional: tornar as animações do dispositivo mais lentas

Como este codelab envolve transições rápidas, mas refinadas, pode ser útil desacelerar as animações do dispositivo para observar alguns dos detalhes mais delicados das transições durante a implementação. Isso pode ser feito com comandos do shell adb ou um bloco de Configurações rápidas. Esses métodos de desaceleração de animações do dispositivo também vão afetar as animações no dispositivo fora do app Reply.

Método 1: comandos de shell do adb

Para desacelerar as animações do dispositivo em um fator de 10x, execute os seguintes comandos na linha de comando:

adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10

Para redefinir a velocidade da animação do dispositivo para o normal, execute os seguintes comandos:

adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1

Método 2: bloco "Configurações rápidas"

Como alternativa, para configurar o bloco "Configurações rápidas", primeiro ative as "Configurações do desenvolvedor" no seu dispositivo, caso não tenha feito isso antes:

  1. Abra o app "Configurações" do dispositivo.
  2. Role a tela para baixo e clique em "Sobre o dispositivo emulado".
  3. Role a tela para baixo e clique rapidamente em "Número da versão" até que as configurações do desenvolvedor sejam ativadas.

Em seguida, faça o seguinte, ainda no app "Configurações" do dispositivo, para ativar o bloco de Configurações rápidas:

  1. Clique no ícone ou na barra de pesquisa na parte de cima da tela.
  2. Digite "blocos" no campo de pesquisa.
  3. Clique na linha "Blocos de desenvolvedor para configurações rápidas".
  4. Clique na chave "Escala de animação da janela".

Por fim, durante o codelab, arraste a aba de notificações do sistema da parte de cima da tela para baixo e use o ícone c7e3f98200023f6a.png para alternar entre animações lentas e normais.

3. Conhecer o código do app de exemplo

Vamos analisar o código. Fornecemos um app que usa a biblioteca componente de navegação do Jetpack para navegar entre alguns fragmentos diferentes, tudo em uma única atividade, MainActivity:

  • HomeFragment: exibe uma lista de e-mails.
  • EmailFragment: exibe um único e-mail completo.
  • ComposeFragment: permite escrever um novo e-mail.
  • SearchFragment:exibe uma visualização de pesquisa.

Primeiro, para entender como o gráfico de navegação do app é configurado, abra o navigation_graph.xml no diretório app -> src -> main -> res -> navigation:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/navigation_graph"
   app:startDestination="@id/homeFragment">

   <fragment
       android:id="@+id/homeFragment"
       android:name="com.materialstudies.reply.ui.home.HomeFragment"
       android:label="HomeFragment">
       <argument...>
       <action
           android:id="@+id/action_homeFragment_to_emailFragment"
           app:destination="@id/emailFragment" />
   </fragment>
   <fragment
       android:id="@+id/emailFragment"
       android:name="com.materialstudies.reply.ui.email.EmailFragment"
       android:label="EmailFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/composeFragment"
       android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
       android:label="ComposeFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/searchFragment"
       android:name="com.materialstudies.reply.ui.search.SearchFragment"
       android:label="SearchFragment" />
   <action
       android:id="@+id/action_global_homeFragment"
       app:destination="@+id/homeFragment"
       app:launchSingleTop="true"
       app:popUpTo="@+id/navigation_graph"
       app:popUpToInclusive="true"/>
   <action
       android:id="@+id/action_global_composeFragment"
       app:destination="@+id/composeFragment" />
   <action
       android:id="@+id/action_global_searchFragment"
       app:destination="@+id/searchFragment" />
</navigation>

Observe como todos os fragmentos mencionados acima estão presentes, com o fragmento de inicialização padrão definido como HomeFragment via app:startDestination="@id/homeFragment". Essa definição XML do gráfico de destino do fragmento, assim como as ações, informa o código de navegação Kotlin gerado que você vai encontrar ao vincular transições.

activity_main.xml (link em inglês)

Em seguida, observe o layout activity_main.xml no diretório app -> src -> main -> res -> layout. Você vai encontrar o NavHostFragment, que é configurado com o gráfico de navegação acima:

<fragment
   android:id="@+id/nav_host_fragment"
   android:name="androidx.navigation.fragment.NavHostFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:defaultNavHost="true"
   app:navGraph="@navigation/navigation_graph"/>

Esse NavHostFragment preenche a tela e processa todas as mudanças de navegação de fragmento em tela cheia no app. O BottomAppBar e o FloatingActionButton ancorado, também em activity_main.xml, são dispostos sobre o fragmento atual exibido pelo NavHostFragment e, portanto, são mostrados ou ocultados dependendo do destino do fragmento pelo código de exemplo do app fornecido.

Além disso, o BottomNavDrawerFragment em activity_main.xml é uma gaveta na parte de baixo da tela com um menu para navegar entre as diferentes caixas de e-mail. Isso é mostrado condicionalmente pelo botão com o logotipo de resposta BottomAppBar.

MainActivity.kt

Por fim, para conferir um exemplo de uma ação de navegação em uso, abra MainActivity.kt no diretório app -> src -> main -> java -> com.materialstudies.reply.ui. Localize a função navigateToSearch(), que vai ficar assim:

private fun navigateToSearch() {
   val directions = SearchFragmentDirections.actionGlobalSearchFragment()
   findNavController(R.id.nav_host_fragment).navigate(directions)
}

Isso mostra como navegar até a página de visualização de pesquisa sem transições personalizadas. Neste codelab, você vai conhecer a MainActivity do Reply e quatro fragmentos principais para configurar transições do Material Design que funcionam em conjunto com as várias ações de navegação do app.

Agora que você já conhece o código inicial, vamos implementar nossa primeira transição.

4. Adicionar uma transição de transformação de contêiner da lista de e-mails para a página de detalhes

Para começar, adicione uma transição ao clicar em um e-mail. Para essa mudança de navegação, o padrão de transformação de contêiner é adequado, já que foi projetado para transições entre elementos da interface que incluem um contêiner. Ele cria uma conexão visível entre dois elementos da interface.

Antes de adicionar qualquer código, execute o app Reply e clique em um e-mail. Ele fará um simples corte, ou seja, a tela será substituída sem transição:

f0e8a92eb2216bce.gif

Comece adicionando um atributo transitionName ao MaterialCardView em email_item_layout.xml, conforme mostrado no snippet a seguir:

email_item_layout.xml

android:transitionName="@{@string/email_card_transition_name(email.id)}"

O nome da transição usa um recurso de string com um parâmetro. É necessário usar o ID de cada e-mail para garantir que o transitionName na EmailFragment seja exclusivo.

Agora que o nome de transição do item da lista de e-mails foi definido, vamos fazer o mesmo no layout de detalhes do e-mail. Em fragment_email.xml, defina o transitionName da MaterialCardView como o seguinte recurso de string:

fragment_email.xml

android:transitionName="@string/email_card_detail_transition_name"

Em HomeFragment.kt, substitua o código em onEmailClicked pelo snippet abaixo para criar o mapeamento na visualização inicial (item da lista de e-mails) e final (tela de detalhes do e-mail):

HomeFragment.kt

val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)

Agora que o encanamento está configurado, é possível criar uma transformação de contêiner. No método EmailFragment onCreate, defina sharedElementEnterTransition como uma nova instância de um MaterialContainerTransform (importando a versão com.google.android.material.transition em vez da com.google.android.material.transition.platform) adicionando o seguinte snippet:

EmailFragment.kt

sharedElementEnterTransition = MaterialContainerTransform().apply {
   drawingViewId = R.id.nav_host_fragment
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}

Agora, execute o app novamente.

ed62cedec31da268.gif

Tudo está ficando ótimo. Quando você clica em um e-mail na lista, uma transformação de contêiner expande o item da lista para uma página de detalhes em tela cheia. No entanto, o botão "Voltar" não recolhe o e-mail na lista. Além disso, a lista de e-mails desaparece imediatamente no início da transição, mostrando o plano de fundo da janela cinza. Ou seja, o trabalho ainda não terminou.

Para corrigir a transição de retorno, adicione as duas linhas abaixo ao método onViewCreated em HomeFragment.kt:

HomeFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

Tente executar o app novamente. Se você pressionar "Voltar" após abrir um e-mail, ele será recolhido de volta para a lista. Legal! Vamos continuar melhorando a animação.

O problema do desaparecimento da lista de e-mails ocorre porque, ao navegar para um novo fragmento usando o componente de navegação, o fragmento atual é imediatamente removido e substituído pelo novo fragmento recebido. Para manter a lista de e-mails visível mesmo depois de ser substituída, adicione uma transição de saída a HomeFragment.

Adicione o snippet abaixo ao método HomeFragment onEmailClicked para que a lista de e-mails seja dimensionada sutilmente ao sair e voltar ao entrar ao entrar novamente:

HomeFragment.kt

exitTransition = MaterialElevationScale(false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Em seguida, para garantir que a transição MaterialElevationScale seja aplicada à tela inicial como um todo, em vez de a cada uma das visualizações individuais na hierarquia, marque o RecyclerView em fragment_home.xml como um grupo de transição.

fragment_home.xml

android:transitionGroup="true"

Nesta fase, você já tem uma transformação de contêiner em funcionamento. Se você clicar em um e-mail, o item da lista será expandido para uma tela de detalhes enquanto a lista de e-mails for ocultada. Se você pressionar "Voltar", a tela de detalhes do e-mail será recolhida e a lista de e-mails voltará a aparecer.

9df2b39d5a150418.gif

5. Adicionar uma transição de transformação de contêiner do FAB para a página "Escrever e-mail"

Vamos continuar com a transformação de contêiner e adicionar uma transição do botão de ação flutuante para o ComposeFragment, expandindo o FAB para um novo e-mail a ser gravado pelo usuário. Primeiro, execute o app novamente e clique no FAB. Você verá que não há transição ao abrir a tela "Escrever e-mail".

d242c9708abd382c.gif

Embora usemos a mesma classe de transição, a forma como configuramos essa instância é diferente, já que nosso FAB fica no MainActivity e nosso ComposeFragment é colocado dentro do contêiner do host de navegação MainActivity.

Em ComposeFragment.kt, adicione o snippet abaixo ao método onViewCreated, certificando-se de importar a versão androidx.transition de Slide.

ComposeFragment.kt

enterTransition = MaterialContainerTransform().apply {
   startView = requireActivity().findViewById(R.id.fab)
   endView = emailCardView
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   containerColor = requireContext().themeColor(R.attr.colorSurface)
   startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
   endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
   addTarget(R.id.email_card_view)
}

Além dos parâmetros usados para configurar a transformação de contêiner anterior, startView e endView estão sendo definidos manualmente aqui. Em vez de usar atributos transitionName para informar ao sistema de transição do Android quais visualizações precisam ser transformadas, especifique-as manualmente quando necessário.

Agora, execute o app novamente. O FAB vai se transformar na tela de composição (confira o GIF no final desta etapa).

Assim como na etapa anterior, é necessário adicionar uma transição à HomeFragment para evitar que ela desapareça após ser removida e substituída por ComposeFragment.

Copie o snippet abaixo no método navigateToCompose na MainActivity antes da chamada NavController navigate.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialElevationScale(false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialElevationScale(true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Pronto, concluímos esta etapa. Agora você tem uma transição do FAB para a tela "Escrever e-mail" com a seguinte aparência:

81b68391ac4b0a9.gif

6. Adicionar uma transição de eixo z compartilhado do ícone de pesquisa para a página de visualização de pesquisa

Nesta etapa, adicionaremos uma transição do ícone de pesquisa para a visualização de pesquisa em tela cheia. Como não há um contêiner persistente envolvido nessa mudança de navegação, podemos usar uma transição de eixo z compartilhado para reforçar a relação espacial entre as duas telas e indicar o movimento para um nível acima na hierarquia do app.

Antes de adicionar mais código, execute o app e toque no ícone de pesquisa no canto inferior direito da tela. Essa ação exibirá a tela de visualização da pesquisa sem transição.

499e1a677b4216bb.gif

Para começar, encontre o método navigateToSearch em MainActivity e adicione o seguinte snippet de código antes da chamada de método NavController navigate para configurar a saída do fragmento atual e inserir novamente as transições do eixo Z do MaterialSharedAxis.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Em seguida, adicione o snippet de código abaixo ao método onCreate em SearchFragment, que configura as transições de entrada e retorno MaterialSharedAxis.

SearchFragment.kt

enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Por fim, para garantir que a transição MaterialSharedAxis seja aplicada à tela de pesquisa como um todo, em vez de a cada uma das visualizações individuais na hierarquia, marque a LinearLayout em fragment_search.xml como um grupo de transição.

fragment_search.xml

android:transitionGroup="true"

Pronto! Agora, execute novamente o app e toque no ícone de pesquisa. As telas inicial e de visualização da pesquisa serão esmaecidas e redimensionadas simultaneamente ao longo do eixo z em profundidade, criando um efeito contínuo entre as duas telas.

e5c0b0a130e807db.gif

7. Adicionar uma transição de esmaecimento cruzado entre as páginas da caixa de e-mails

Nesta etapa, adicionaremos uma transição entre caixas de e-mails diferentes. Como não queremos enfatizar uma relação espacial ou hierárquica, usaremos um esmaecimento cruzado para fazer uma "troca" simples entre as listas de e-mails.

Antes de adicionar qualquer outro código, tente executar o app. Toque no logotipo do Reply na barra de apps inferior e mude de caixa de e-mails. A lista mudará sem nenhuma transição.

2c874c0a4588e8fb.gif

Para começar, encontre o método navigateToHome em MainActivity e adicione o seguinte snippet de código antes da chamada de método NavController navigate para configurar a transição MaterialFadeThrough de saída do fragmento atual.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialFadeThrough().apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Em seguida, abra HomeFragment. Em onCreate, defina o enterTransition do fragmento como uma nova instância de MaterialFadeThrough.

HomeFragment.kt

enterTransition = MaterialFadeThrough().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Execute o app novamente. Quando você abrir a gaveta de navegação inferior e mudar de caixa de e-mails, a lista de e-mails atual será esmaecida enquanto a nova lista é exibida. Legal!

f61dfd58ea7bd3fd.gif

8. Adicionar uma transição de transformação de contêiner do ícone de endereço de e-mail para a visualização de card

Nesta etapa, você vai adicionar uma transição que transforma um ícone em um card pop-up. Uma transformação de contêiner é usada aqui para ajudar a informar ao usuário que a ação realizada no pop-up afetará o ícone de origem do pop-up.

Antes de adicionar qualquer código, execute o app Reply, clique em um e-mail, clique no FAB "responder" e tente clicar no ícone de contato de um destinatário. O ícone vai desaparecer instantaneamente, e um card com os endereços de e-mail do contato vai aparecer sem animações.

6200c682da2382d5.gif

Você vai trabalhar em ComposeFragment nesta etapa. Já foram adicionados ao layout ComposeFragment os ícones de destinatário (visíveis por padrão) e um card de destinatário (invisível por padrão). Um ícone de destinatário e esse cartão são as duas visualizações em que você vai criar uma transformação de contêiner.

Para começar, abra ComposeFragment e encontre o método expandChip. Esse método é chamado quando o chip fornecido é clicado. Adicione o snippet de código a seguir acima das linhas que trocam as visibilidades recipientCardView e chip. Isso acionará a transformação de contêiner registrada via beginDelayedTransition.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = chip
   endView = binding.recipientCardView
   scrimColor = Color.TRANSPARENT
   endElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(binding.recipientCardView)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Se você executar o app agora, o ícone vai se transformar em um card de endereços de e-mail para o destinatário. Em seguida, vamos configurar a transição de retorno para retrair o cartão de volta ao chip.

No método collapseChip da ComposeFragment, adicione o snippet de código abaixo para recolher o card no ícone.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = binding.recipientCardView
   endView = chip
   scrimColor = Color.TRANSPARENT
   startElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(chip)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Execute o app novamente. Ao clicar no ícone, ele se expande para um card. Já ao clicar no card, o card voltará ao ícone. Legal!

e823b28e2890e05d.gif

9. Tudo pronto

Usando menos de 100 linhas de código Kotlin e algumas marcações XML básicas, a biblioteca MDC-Android ajudou você a criar transições bonitas em um app existente que segue as diretrizes do Material Design. Além disso, a aparência e o comportamento das transições são consistentes em todos os dispositivos Android.

454a47ba96017a25.gif

Próximas etapas

Para ver mais informações sobre o sistema de movimento do Material Design, consulte as especificações e a documentação completa do desenvolvedor (links em inglês). Tente adicionar algumas transições do Material Design ao seu app.

Agradecemos por testar o movimento do Material Design. Esperamos que tenha gostado deste codelab.

Este codelab exigiu esforço e tempo normais para ser concluído

Concordo totalmente Concordo Não concordo nem discordo Discordo Discordo totalmente

Quero continuar usando o sistema de movimento do Material Design no futuro

Concordo totalmente Concordo Não concordo nem discordo Discordo Discordo totalmente