Crea splendide transizioni con Material Motion per Android

1. Introduzione

Material Design è un sistema per creare prodotti digitali audaci e belli. Unendo stile, branding, interazione e movimento in un insieme coerente di principi e componenti, i team di prodotto possono realizzare il loro massimo potenziale di progettazione.

logo_components_color_2x_web_96dp.png

I componenti Material (MDC) aiutano gli sviluppatori a implementare Material Design. Creato da un team di ingegneri e progettisti UX di Google, MDC include decine di componenti UI belli e funzionali ed è disponibile per Android, iOS, web e Flutter.material.io/develop

Che cos'è il sistema di movimento di Material per Android?

Il sistema di movimento Material per Android è un insieme di pattern di transizione all'interno della libreria MDC-Android che possono aiutare gli utenti a comprendere e navigare in un'app, come descritto nelle linee guida di Material Design.

I quattro principali pattern di transizione di Material sono i seguenti:

  • Trasformazione del contenitore:transizioni tra elementi UI che includono un contenitore; crea un collegamento visibile tra due elementi UI distinti trasformando senza problemi un elemento in un altro.
  • Asse condiviso:transizioni tra gli elementi UI che hanno una relazione di spazio o di navigazione; utilizza una trasformazione condivisa sugli assi x, y o z per rafforzare la relazione tra gli elementi.
  • Dissolvenza tramite: transizioni tra elementi UI che non hanno una forte correlazione; utilizza una dissolvenza in uscita e in entrata sequenziale, con una scalabilità dell'elemento in entrata.
  • Dissolvenza:utilizzata per gli elementi UI che entrano o escono dai limiti dello schermo.

La libreria MDC-Android offre classi di transizione per questi pattern, basate sia sulla libreria AndroidX Transition (androidx.transition) sia sull'Android Transition Framework (android.transition):

AndroidX

  • Disponibile nel pacchetto com.google.android.material.transition
  • Supporta il livello API 14 e versioni successive
  • Supporta frammenti e visualizzazioni, ma non attività o finestre
  • Contiene correzioni di bug di cui è stato eseguito il porting e un comportamento coerente tra i livelli API

Framework

  • Disponibile nel pacchetto com.google.android.material.transition.platform
  • Supporta il livello API 21 e versioni successive
  • Supporta frammenti, visualizzazioni, attività e finestre
  • Correzioni di bug non sottoposte a backporting e che potrebbero avere un comportamento diverso nei vari livelli API

In questo codelab utilizzerai le transizioni Material create sulla libreria AndroidX, il che significa che ti concentrerai principalmente su Fragment e View.

Cosa creerai

Questo codelab ti guiderà nella creazione di alcune transizioni in un'app di posta elettronica Android di esempio chiamata Reply, utilizzando Kotlin, per dimostrare come puoi utilizzare le transizioni della libreria MDC-Android per personalizzare l'aspetto della tua app.

Verrà fornito il codice iniziale per l'app Reply e incorporerai le seguenti transizioni Material nell'app, che possono essere visualizzate nella GIF del codelab completato di seguito:

  • Transizione Trasformazione contenitore dall'elenco email alla pagina dei dettagli dell'email
  • Transizione Trasformazione del contenitore dal pulsante Azione flottante alla pagina di composizione dell'email
  • Transizione asse Z condiviso dall'icona di ricerca alla pagina della visualizzazione di ricerca
  • Transizione Dissolvenza tra le pagine della casella di posta
  • Transizione Container Transform dal chip dell'indirizzo email alla visualizzazione schede

Il dominio dell'iframe richiesto (youtu.be) non è stato autorizzato.

Che cosa ti serve

  • Conoscenza di base dello sviluppo Android e di Kotlin
  • Android Studio (scaricalo qui se non lo hai già)
  • Un emulatore o un dispositivo Android (disponibile tramite Android Studio)
  • Il codice campione (vedi il passaggio successivo)

Come valuteresti il tuo livello di esperienza nella creazione di app per Android?

Principiante Intermedio Avanzato

2. Configurazione dell'ambiente di sviluppo

Avviare Android Studio

Quando apri Android Studio, dovrebbe essere visualizzata una finestra con il titolo "Welcome to Android Studio" (Benvenuto in Android Studio). Tuttavia, se è la prima volta che avvii Android Studio, segui i passaggi della procedura guidata di configurazione di Android Studio con i valori predefiniti. Il download e l'installazione dei file necessari per questo passaggio possono richiedere diversi minuti, quindi puoi lasciarlo in esecuzione in background mentre svolgi la sezione successiva.

Opzione 1: clona l'app codelab iniziale da GitHub

Per clonare questo codelab da GitHub, esegui questi comandi:

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

Opzione 2: scarica il file zip dell'app codelab iniziale

L'app di base si trova nella directory material-components-android-motion-codelab-develop.

Caricare il codice di avvio in Android Studio

  1. Al termine della configurazione guidata e alla visualizzazione della finestra Welcome to Android Studio (Benvenuto in Android Studio), fai clic su Open an existing Android Studio project (Apri un progetto Android Studio esistente).

e3f200327a67a53.png

  1. Vai alla directory in cui hai installato il codice campione e seleziona la directory di esempio per aprire il progetto.
  2. Attendi un momento che Android Studio crei e sincronizzi il progetto, come indicato dagli indicatori di attività nella parte inferiore della finestra di Android Studio.
  1. A questo punto, Android Studio potrebbe generare alcuni errori di build perché mancano l'SDK Android o gli strumenti di build, ad esempio quello mostrato di seguito. Segui le istruzioni in Android Studio per installare/aggiornare questi elementi e sincronizzare il progetto. Se continui a riscontrare problemi, segui la guida sull'aggiornamento degli strumenti con SDK Manager.

6e026ae171f5b1eb.png

Verifica le dipendenze del progetto

Il progetto richiede una dipendenza dalla libreria MDC-Android. Il codice campione che hai scaricato dovrebbe già avere questa dipendenza elencata, ma diamo un'occhiata alla configurazione per assicurarci.

Vai al file build.gradle del modulo app e assicurati che il blocco dependencies includa una dipendenza da MDC-Android:

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

Esegui l'app di base

  1. Assicurati che la configurazione di compilazione a sinistra della scelta del dispositivo sia app.
  2. Premi il pulsante verde Esegui / Riproduci per creare ed eseguire l'app.

24218d0a6ae25803.png

  1. Nella finestra Seleziona destinazione di distribuzione, se hai già un dispositivo Android elencato nei dispositivi disponibili, vai al passaggio 8. In caso contrario, fai clic su Crea nuovo dispositivo virtuale.
  2. Nella schermata Seleziona hardware, seleziona un dispositivo smartphone, ad esempio Pixel 3, e poi fai clic su Avanti.
  3. Nella schermata Immagine di sistema, seleziona una versione recente di Android, preferibilmente il livello API più alto. Se non è installato, fai clic sul link Scarica mostrato e completa il download.
  4. Fai clic su Avanti.
  5. Nella schermata Android Virtual Device (AVD), lascia le impostazioni invariate e fai clic su Fine.
  6. Seleziona un dispositivo Android dalla finestra di dialogo Destinazione di deployment.
  7. Fai clic su Ok.
  8. Android Studio crea l'app, la esegue il deployment e la apre automaticamente sul dispositivo di destinazione.

Operazione riuscita. Il codice di avvio per la home page di Reply deve essere in esecuzione nell'emulatore. Dovresti visualizzare la posta in arrivo contenente un elenco di email.

cc73eb0d0f779035.png

(Facoltativo) Rallentare le animazioni del dispositivo

Poiché questo codelab prevede transizioni rapide ma raffinate, può essere utile rallentare le animazioni del dispositivo per osservare alcuni dei dettagli più fini delle transizioni durante l'implementazione. Puoi farlo con i comandi della shell adb o con un riquadro Impostazioni rapide. Tieni presente che questi metodi per rallentare le animazioni del dispositivo influiranno anche sulle animazioni del dispositivo al di fuori dell'app Reply.

Metodo 1: comandi della shell ADB

Per rallentare le animazioni del dispositivo di un fattore 10x, puoi eseguire i seguenti comandi dalla riga di 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

Per ripristinare la velocità di animazione normale del dispositivo, esegui i seguenti comandi:

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

Metodo 2: riquadro Impostazioni rapide

In alternativa, per configurare il riquadro Impostazioni rapide, attiva prima le Impostazioni sviluppatore sul dispositivo, se non l'hai già fatto:

  1. Apri l'app "Impostazioni" del dispositivo.
  2. Scorri verso il basso fino in fondo e fai clic su "Informazioni sul dispositivo emulato".
  3. Scorri verso il basso fino alla fine e fai clic rapidamente su "Numero build" finché le Impostazioni sviluppatore non sono attive.

Quindi, esegui le seguenti operazioni, sempre all'interno dell'app "Impostazioni" del dispositivo, per attivare il riquadro Impostazioni rapide:

  1. Fai clic sull'icona di ricerca o sulla barra di ricerca nella parte superiore dello schermo.
  2. Digita "riquadri" nel campo di ricerca.
  3. Fai clic sulla riga "Riquadri sviluppatore per impostazioni rapide".
  4. Fai clic sull'opzione "Scala animazione finestra".

Infine, durante il codelab, abbassa l'area notifiche di sistema dalla parte superiore dello schermo e utilizza l'icona c7e3f98200023f6a.png per alternare le animazioni a velocità normale e lenta.

3. Familiarizzare con il codice dell'app di esempio

Diamo un'occhiata al codice. Abbiamo fornito un'app che utilizza la libreria del componente di navigazione Jetpack per spostarsi tra alcuni Fragment diversi, il tutto all'interno di una singola attività, MainActivity:

  • HomeFragment: mostra un elenco di email
  • EmailFragment:mostra una singola email completa
  • ComposeFragment:consente di comporre una nuova email
  • SearchFragment: mostra una visualizzazione di ricerca

Innanzitutto, per capire come è configurato il grafico di navigazione dell'app, apri navigation_graph.xml nella directory 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>

Prendi nota di come sono presenti tutti i frammenti menzionati sopra, con il frammento di avvio predefinito impostato su HomeFragment tramite app:startDestination="@id/homeFragment". Questa definizione XML del grafico di destinazione del frammento, nonché le azioni, informa il codice di navigazione Kotlin generato che incontrerai durante il collegamento delle transizioni.

activity_main.xml

Successivamente, dai un'occhiata al layout activity_main.xml nella directory app -> src -> main -> res -> layout. Vedrai NavHostFragment, configurato con il grafico di navigazione riportato sopra:

<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"/>

Questo NavHostFragment riempie lo schermo e gestisce tutte le modifiche alla navigazione dei frammenti a schermo intero nell'app. Il BottomAppBar e il relativo FloatingActionButton ancorato, anch'esso in activity_main.xml, sono disposti sopra il frammento corrente visualizzato da NavHostFragment e pertanto verranno mostrati o nascosti a seconda della destinazione del frammento in base al codice dell'app di esempio fornito.

Inoltre, il BottomNavDrawerFragment in activity_main.xml è un riquadro a scomparsa inferiore che contiene un menu per navigare tra le diverse caselle di posta, che viene mostrato in modo condizionale tramite il pulsante con il logo BottomAppBar Rispondi.

MainActivity.kt

Infine, per vedere un esempio di azione di navigazione in uso, apri MainActivity.kt nella directory app -> src -> main -> java -> com.materialstudies.reply.ui. Individua la funzione navigateToSearch(), che dovrebbe avere il seguente aspetto:

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

Questo mostra come passare alla pagina della visualizzazione di ricerca senza alcuna transizione personalizzata. Durante questo codelab, esaminerai la MainActivity e quattro frammenti principali di Reply per configurare le transizioni Material che funzionano in tandem con le varie azioni di navigazione nell'app.

Ora che hai familiarità con il codice di avvio, implementiamo la nostra prima transizione.

4. Aggiungere la transizione Trasformazione del contenitore dalla mailing list alla pagina dei dettagli dell'email

Per iniziare, aggiungi una transizione quando fai clic su un'email. Per questa modifica della navigazione, il pattern di trasformazione del contenitore è particolarmente adatto, in quanto è progettato per le transizioni tra elementi UI che includono un contenitore. Questo pattern crea un collegamento visibile tra due elementi UI.

Prima di aggiungere qualsiasi codice, prova a eseguire l'app Reply e a fare clic su un'email. Dovrebbe essere un semplice jump cut, ovvero lo schermo viene sostituito senza transizione:

f0e8a92eb2216bce.gif

Inizia aggiungendo un attributo transitionName a MaterialCardView in email_item_layout.xml come mostrato nello snippet seguente:

email_item_layout.xml

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

Il nome della transizione accetta una risorsa stringa con un parametro. Devi utilizzare l'ID di ogni email per assicurarti che ogni transitionName nel nostro EmailFragment sia univoco.

Ora che hai impostato il nome della transizione dell'elemento dell'elenco email, facciamo lo stesso nel layout dei dettagli dell'email. In fragment_email.xml, imposta transitionName di MaterialCardView sulla seguente risorsa stringa:

fragment_email.xml

android:transitionName="@string/email_card_detail_transition_name"

In HomeFragment.kt, sostituisci il codice in onEmailClicked con lo snippet riportato di seguito per creare la mappatura dalla visualizzazione iniziale (elemento della mailing list) alla visualizzazione finale (schermata dei dettagli dell'email):

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)

Ora che hai configurato l'infrastruttura, puoi creare una trasformazione del container. Nel metodo EmailFragment onCreate, imposta sharedElementEnterTransition su una nuova istanza di un MaterialContainerTransform (importando la versione com.google.android.material.transition anziché la versione com.google.android.material.transition.platform) aggiungendo il seguente 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))
}

Ora prova a eseguire di nuovo l'app.

ed62cedec31da268.gif

Le cose iniziano ad andare alla grande. Quando fai clic su un'email nell'elenco, una trasformazione del contenitore deve espandere l'elemento dell'elenco in una pagina dei dettagli a schermo intero. Tuttavia, nota che premendo Indietro l'email non viene compressa di nuovo nell'elenco. Inoltre, la mailing list scompare immediatamente all'inizio della transizione, mostrando lo sfondo grigio della finestra. Quindi non abbiamo ancora finito.

Per correggere la transizione di ritorno, aggiungi le due righe seguenti al metodo onViewCreated in HomeFragment.kt:

HomeFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

Prova a eseguire di nuovo l'app. Se premi Indietro dopo aver aperto un'email, questa verrà nuovamente compressa nell'elenco. Bene! Continuiamo a migliorare l'animazione.

Il problema della scomparsa della mailing list si verifica perché, quando si passa a un nuovo frammento utilizzando il componente di navigazione, il frammento corrente viene immediatamente rimosso e sostituito con il nuovo frammento in arrivo. Per mantenere visibile l'elenco email anche dopo la sostituzione, puoi aggiungere una transizione di uscita a HomeFragment.

Aggiungi lo snippet riportato di seguito al metodo HomeFragment onEmailClicked per fare in modo che l'elenco delle email venga ridimensionato in modo impercettibile quando esci e quando rientri:

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()
}

Successivamente, per assicurarti che la transizione MaterialElevationScale venga applicata alla schermata Home nel suo complesso, anziché a ciascuna delle singole visualizzazioni nella gerarchia, contrassegna RecyclerView in fragment_home.xml come gruppo di transizione.

fragment_home.xml

android:transitionGroup="true"

A questo punto, dovresti avere una trasformazione del contenitore completamente funzionante. Se fai clic su un'email, l'elemento dell'elenco si espande in una schermata dei dettagli, mentre l'elenco delle email si ritira. Se premi Indietro, la schermata dei dettagli dell'email viene compressa in un elemento di elenco mentre viene eseguito lo zoom avanti nell'elenco delle email.

9df2b39d5a150418.gif

5. Aggiungi la transizione della trasformazione del contenitore dal FAB alla pagina di composizione dell'email

Continuiamo con la trasformazione del contenitore e aggiungiamo una transizione dal pulsante di azione flottante a ComposeFragment, espandendo il FAB a una nuova email da scrivere. Innanzitutto, esegui di nuovo l'app e fai clic sul FAB per vedere che non c'è transizione all'avvio della schermata di composizione email.

d242c9708abd382c.gif

Sebbene utilizziamo la stessa classe di transizione, il modo in cui configuriamo questa istanza sarà diverso, poiché il nostro FAB si trova in MainActivity e il nostro ComposeFragment è posizionato all'interno del contenitore host di navigazione MainActivity.

In ComposeFragment.kt, aggiungi il seguente snippet al metodo onViewCreated, assicurandoti di importare la versione androidx.transition di 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)
}

Oltre ai parametri utilizzati per configurare la precedente trasformazione del contenitore, startView e endView vengono impostati manualmente qui. Invece di utilizzare gli attributi transitionName per comunicare al sistema di transizione Android quali visualizzazioni devono essere trasformate, puoi specificarle manualmente, se necessario.

Ora esegui di nuovo l'app. Dovresti vedere il FAB che si trasforma nella schermata di composizione (vedi la GIF alla fine di questo passaggio).

Come nel passaggio precedente, devi aggiungere una transizione a HomeFragment per evitare che scompaia dopo essere stato rimosso e sostituito da ComposeFragment.

Copia lo snippet riportato di seguito nel metodo navigateToCompose in MainActivity prima della chiamata 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()
   }
}

Questo passaggio è terminato. Dovresti avere una transizione dal FAB alla schermata di composizione simile alla seguente:

81b68391ac4b0a9.gif

6. Aggiungere la transizione Asse Z condiviso dall'icona di ricerca alla pagina della visualizzazione di ricerca

In questo passaggio, aggiungeremo una transizione dall'icona di ricerca alla visualizzazione di ricerca a schermo intero. Poiché non è coinvolto alcun contenitore persistente in questa modifica della navigazione, possiamo utilizzare una transizione sull'asse Z condiviso per rafforzare la relazione spaziale tra le due schermate e indicare lo spostamento di un livello verso l'alto nella gerarchia dell'app.

Prima di aggiungere altro codice, prova a eseguire l'app e a toccare l'icona di ricerca nell'angolo in basso a destra dello schermo. Dovrebbe essere visualizzata la schermata della visualizzazione di ricerca senza transizione.

499e1a677b4216bb.gif

Per iniziare, trova il metodo navigateToSearch in MainActivity e aggiungi il seguente snippet di codice prima della chiamata al metodo NavController navigate per configurare le transizioni sull'asse Z di uscita e rientro del frammento corrente.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()
   }
}

Aggiungi quindi il seguente snippet di codice al metodo onCreate in SearchFragment, che configura le transizioni di entrata e ritorno 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()
}

Infine, per assicurarti che la transizione MaterialSharedAxis venga applicata alla schermata di ricerca nel suo complesso, anziché a ciascuna delle singole visualizzazioni nella gerarchia, contrassegna LinearLayout in fragment_search.xml come gruppo di transizione.

fragment_search.xml

android:transitionGroup="true"

È tutto. Ora prova a eseguire di nuovo l'app e a toccare l'icona di ricerca. Le schermate della visualizzazione Home e della ricerca devono sbiadire e scalare simultaneamente lungo l'asse Z in profondità, creando un effetto uniforme tra le due schermate.

e5c0b0a130e807db.gif

7. Aggiungere la transizione Dissolvenza tra le pagine della casella di posta

In questo passaggio, aggiungeremo una transizione tra le diverse caselle postali. Poiché non vogliamo enfatizzare una relazione spaziale o gerarchica, utilizzeremo una dissolvenza incrociata per eseguire un semplice "scambio" tra gli elenchi di email.

Prima di aggiungere altro codice, prova a eseguire l'app, tocca il logo Rispondi nella barra delle app inferiore e cambia casella di posta. L'elenco delle email deve cambiare senza transizione.

2c874c0a4588e8fb.gif

Per iniziare, trova il metodo navigateToHome in MainActivity e aggiungi il seguente snippet di codice prima della chiamata al metodo NavController navigate per configurare la transizione MaterialFadeThrough di uscita del frammento corrente.

MainActivity.kt

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

Poi apri HomeFragment. In onCreate, imposta enterTransition del fragment su una nuova istanza di MaterialFadeThrough.

HomeFragment.kt

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

Esegui di nuovo l'app. Quando apri il riquadro di navigazione a scomparsa in basso e cambi casella di posta, l'elenco attuale di email dovrebbe sbiadire e ridursi, mentre il nuovo elenco dovrebbe apparire e ingrandirsi. Bene!

f61dfd58ea7bd3fd.gif

8. Aggiunta della transizione Trasformazione contenitore dal chip dell'indirizzo email alla visualizzazione schede

In questo passaggio, aggiungerai una transizione che trasforma un chip in una scheda popup. Qui viene utilizzata una trasformazione del contenitore per informare l'utente che l'azione intrapresa nel popup influirà sul chip da cui ha avuto origine il popup.

Prima di aggiungere qualsiasi codice, esegui l'app Reply, fai clic su un'email, fai clic sul pulsante di azione rapida "Rispondi" e poi prova a fare clic sul chip di contatto di un destinatario. Il chip dovrebbe scomparire immediatamente e dovrebbe apparire una scheda con gli indirizzi email del contatto senza animazioni.

6200c682da2382d5.gif

Per questo passaggio lavorerai in ComposeFragment. Nel layout ComposeFragment sono già stati aggiunti i chip dei destinatari (visibili per impostazione predefinita) e una scheda dei destinatari (invisibile per impostazione predefinita). Un chip destinatario e questa scheda sono le due visualizzazioni tra cui creerai una trasformazione del contenitore.

Per iniziare, apri ComposeFragment e trova il metodo expandChip. Questo metodo viene chiamato quando si fa clic sul parametro chip fornito. Aggiungi il seguente snippet di codice sopra le righe che scambiano la visibilità di recipientCardView e chip, il che attiverà la trasformazione del contenitore registrata tramite 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 esegui l'app ora, il chip dovrebbe trasformarsi in una scheda di indirizzi email per il destinatario. Successivamente, configuriamo la transizione di ritorno per comprimere la scheda nel chip.

Nel metodo collapseChip in ComposeFragment, aggiungi lo snippet di codice riportato di seguito per comprimere la scheda nel chip.

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)

Esegui di nuovo l'app. Se fai clic sul chip, questo si espande in una scheda, mentre se fai clic sulla scheda, questa si comprime di nuovo nel chip. Bene!

e823b28e2890e05d.gif

9. Fine

Utilizzando meno di 100 righe di codice Kotlin e alcuni markup XML di base, la libreria MDC-Android ti ha aiutato a creare bellissime transizioni in un'app esistente conforme alle linee guida di Material Design e che ha un aspetto e un comportamento coerenti su tutti i dispositivi Android.

454a47ba96017a25.gif

Passaggi successivi

Per saperne di più sul sistema di movimento Material, consulta le specifiche e la documentazione completa per gli sviluppatori e prova ad aggiungere alcune transizioni Material alla tua app.

Grazie per aver provato il movimento Material. Ci auguriamo che questo codelab ti sia piaciuto.

Sono riuscito a completare questo codelab con un ragionevole dispendio di tempo e impegno

Totalmente d'accordo D'accordo Indifferente In disaccordo Totalmente in disaccordo

Vorrei continuare a utilizzare il sistema di movimento Material in futuro

Totalmente d'accordo D'accordo Indifferente In disaccordo Totalmente in disaccordo