Gestisci l'animazione e l'animazione dei widget con MotionLayout

MotionLayout è un tipo di layout che ti aiuta a gestire il movimento e l'animazione dei widget nella tua app. MotionLayout è una sottoclasse di ConstraintLayout e si basa sulle sue funzionalità di layout. Nell'ambito della raccolta ConstraintLayout, MotionLayout è disponibile come libreria di supporto.

MotionLayout colma il divario tra le transizioni di layout e i movimenti complessi. e la gestione dell'ambiente, che offre una combinazione di funzionalità tra l'animazione della proprietà Google Cloud, TransitionManager e CoordinatorLayout

Figura 1. Movimenti semplici controllati al tocco.

Oltre a descrivere le transizioni tra i layout, MotionLayout ti consente di anima tutte le proprietà del layout. Inoltre, supporta intrinsecamente transizioni. Ciò significa che puoi mostrare immediatamente qualsiasi punto della transizione in base ad alcune condizioni, ad esempio l'input tocco. MotionLayout supporta anche fotogrammi chiave, consentendo transizioni completamente personalizzate in base alle tue esigenze.

MotionLayout è un valore completamente dichiarativo, il che significa che puoi descrivere qualsiasi transizione in XML, indipendentemente dalla complessità.

Considerazioni sulla progettazione

L'elemento MotionLayout è destinato a spostare, ridimensionare e animare elementi UI con cui come i pulsanti e le barre dei titoli. Non usare i movimenti nella tua app come un effetto speciale senza costi. Utilizzalo per aiutare gli utenti a capire cos'è la tua app facendo. Per ulteriori informazioni sulla progettazione della tua app con il movimento, consulta le Sezione di Material Design Informazioni movimento.

Inizia

Segui questi passaggi per iniziare a utilizzare MotionLayout nel tuo progetto.

  1. Aggiungi la dipendenza ConstraintLayout: da utilizzare MotionLayout nel tuo progetto, aggiungi ConstraintLayout Dipendenza di 2.0 dalla tua app build.gradle. Se utilizzi AndroidX, aggiungi il la seguente dipendenza:

    Alla moda

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha14"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha14")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14")
    }
    
  2. Crea un file MotionLayout: MotionLayout è una sottoclasse di ConstraintLayout, quindi puoi trasformare qualsiasi ConstraintLayout esistente in un MotionLayout di sostituendo il nome della classe nel file di risorse di layout, come mostrato nell' i seguenti esempi:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    Libreria di supporto

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    Ecco un esempio completo di file MotionLayout, che definisce il layout mostrato nella figura 1:

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    Libreria di supporto

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. Creare una scena MotionScene: nell'evento MotionLayout precedente Ad esempio, l'attributo app:layoutDescription fa riferimento a un scena di movimento. Una scena di movimento è un file di risorse XML. All'interno del <MotionScene> dell'elemento principale, una scena in movimento contiene tutte le descrizioni del movimento layout corrispondente. Per mantenere le informazioni sul layout separate dal movimento descrizioni, ogni MotionLayout fa riferimento a un movimento separato scena. Le definizioni della scena in movimento hanno la precedenza su qualsiasi definizione definizioni nel MotionLayout.

    Ecco un esempio di file di scena di movimento che descrive la base orizzontale movimento nella figura 1:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    Nota:

    • <Transition> contiene la definizione base del movimento.

      • motion:constraintSetStart e motion:constraintSetEnd sono riferimenti alla le estremità del movimento. Questi endpoint sono definiti <ConstraintSet> elementi più avanti nella scena in movimento.

      • motion:duration specifica il numero di millisecondi necessario per il completamento del movimento.

    • <OnSwipe> consente di creare un controllo touch per il movimento.

      • motion:touchAnchorId si riferisce alla visualizzazione che l'utente può scorri e trascina.

      • motion:touchAnchorSide indica viene trascinata dal lato destro.

      • motion:dragDirection si riferisce all'avanzamento direzione del trascinamento. Ad esempio: motion:dragDirection="dragRight" indica i progressi aumenta man mano che la visualizzazione viene trascinata verso destra.

    • <ConstraintSet> è il punto in cui definisci i vari vincoli che descrivono il tuo movimento. In questo esempio, viene definito un <ConstraintSet> per ogni punto finale del movimento. Questi endpoint sono centrati verticalmente utilizzando app:layout_constraintTop_toTopOf="parent" e app:layout_constraintBottom_toBottomOf="parent". Orizzontalmente, i punti finali si trovano ai lati più a sinistra e a destra della schermo.

    Per una visione più dettagliata dei vari elementi di una scena in movimento supporta, consulta Esempi di layout di animazione.

Attributi interpolati

All'interno di un file di scena di movimento, ConstraintSet elementi possono contenere elementi aggiuntivi che vengono interpolati durante la transizione. Oltre alla posizione e alla limiti, i seguenti attributi vengono interpolati da MotionLayout:

  • alpha
  • visibility
  • elevation
  • rotation, rotationX e rotationY
  • translationX, translationY e translationZ
  • scaleX, scaleY

Attributi personalizzati

All'interno di un elemento <Constraint>, puoi utilizzare l'elemento <CustomAttribute> per specificare una transizione per gli attributi che non sono semplicemente correlati alla posizione o a View attributi.

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

Un <CustomAttribute> contiene due attributi propri:

  • motion:attributeName è obbligatorio e deve corrispondere a un oggetto con getter e metodi di impostazione. Il getter e il setter devono corrispondere a un pattern specifico. Per ad esempio backgroundColor è supportato, poiché la vista presenta elementi Metodi getBackgroundColor() e setBackgroundColor().
  • L'altro attributo che devi fornire si basa sul tipo di valore. Scegli da supportati i seguenti tipi:
    • motion:customColorValue per i colori
    • motion:customIntegerValue per i numeri interi
    • motion:customFloatValue per i dati in virgola mobile
    • motion:customStringValue per le stringhe
    • motion:customDimension per le dimensioni
    • motion:customBoolean per i valori booleani

Quando specifichi un attributo personalizzato, definisci i valori endpoint sia nel percorso iniziale gli elementi <ConstraintSet> finali.

Cambia il colore dello sfondo

Basandoti sull'esempio precedente, supponi di voler cambiare i colori della visualizzazione come parte del suo moto, come mostrato nella Figura 2.

Figura 2. La visualizzazione cambia il colore di sfondo a mano a mano che si sposta.

Aggiungi un elemento <CustomAttribute> a ogni elemento ConstraintSet, come mostrato in il seguente snippet di codice:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

Attributi aggiuntivi di MotionLayout

Oltre agli attributi dell'esempio precedente, MotionLayout ha altri che potresti voler specificare:

  • app:applyMotionScene="boolean" indica se applicare la scena in movimento. Il valore predefinito di questo attributo è true.
  • app:showPaths="boolean" indica se mostrare i percorsi di animazione come il movimento è in esecuzione. Il valore predefinito di questo attributo è false.
  • app:progress="float" ti consente di specificare esplicitamente l'avanzamento della transizione. Tu puoi utilizzare qualsiasi valore in virgola mobile da 0 (l'inizio della transizione) a 1 (la fine della transizione).
  • app:currentState="reference" consente di specificare un valore ConstraintSet specifico.
  • app:motionDebug consente di visualizzare ulteriori informazioni di debug sull'argomento movimento. I valori possibili sono "SHOW_PROGRESS", "SHOW_PATH" o "SHOW_ALL".

Risorse aggiuntive

Per saperne di più su MotionLayout, consulta le seguenti risorse: