Bewegungen und Widget-Animationen mit MotionLayout verwalten

MotionLayout ist ein Layouttyp, mit dem Sie Bewegungen und Widget-Animationen in Ihrer App verwalten können. MotionLayout ist eine abgeleitete Klasse von ConstraintLayout und baut auf seinen umfassenden Layoutfunktionen auf. Als Teil der ConstraintLayout-Bibliothek ist MotionLayout als Supportbibliothek verfügbar.

MotionLayout schließt die Lücke zwischen Layoutübergängen und komplexer Bewegungsbehandlung und bietet eine Mischung aus Funktionen aus dem Framework für die Property-Animation, TransitionManager und CoordinatorLayout.

Abbildung 1. Grundlegende berührungsgesteuerte Bewegung.

Mit MotionLayout können Sie nicht nur Übergänge zwischen Layouts beschreiben, sondern auch beliebige Layouteigenschaften animieren. Darüber hinaus unterstützt es suchbare Übergänge. Dies bedeutet, dass Sie basierend auf bestimmten Bedingungen sofort jeden Punkt innerhalb des Übergangs anzeigen können, z. B. die Eingabe per Berührung. MotionLayout unterstützt auch Keyframes, sodass vollständig benutzerdefinierte Übergänge an Ihre Anforderungen angepasst werden können.

MotionLayout ist vollständig deklarativ, d. h., Sie können alle Übergänge in XML beschreiben, unabhängig davon, wie komplex.

Überlegungen zum Design

MotionLayout dient zum Verschieben, Anpassen und Animieren von UI-Elementen, mit denen Nutzer interagieren, z. B. Schaltflächen und Titelleisten. Verwenden Sie Bewegungen in Ihrer App nicht als Spezialeffekt. Verwenden Sie es, um Nutzern zu vermitteln, was Ihre App tut. Weitere Informationen zum Design deiner App mit Bewegung findest du im Material Design-Abschnitt Informationen zu Bewegungen.

Erste Schritte

Führen Sie die folgenden Schritte aus, um MotionLayout in Ihrem Projekt zu verwenden.

  1. Fügen Sie die ConstraintLayout-Abhängigkeit hinzu: Wenn Sie MotionLayout in Ihrem Projekt verwenden möchten, fügen Sie die ConstraintLayout 2.0-Abhängigkeit in die Datei build.gradle Ihrer App ein. Wenn Sie AndroidX verwenden, fügen Sie die folgende Abhängigkeit hinzu:

    Groovig

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

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha13")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13")
    }
    
  2. Erstellen Sie eine MotionLayout-Datei: MotionLayout ist eine abgeleitete Klasse von ConstraintLayout. Sie können also alle vorhandenen ConstraintLayout in eine MotionLayout umwandeln. Dazu ersetzen Sie den Klassennamen in Ihrer Layout-Ressourcendatei, wie in den folgenden Beispielen gezeigt:

    AndroidX

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

    Supportbibliothek

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

    Hier ist ein vollständiges Beispiel für eine MotionLayout-Datei, in der das in Abbildung 1 gezeigte Layout definiert wird:

    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>
            

    Supportbibliothek

    <?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. Eine MotionScene erstellen: Im vorherigen MotionLayout-Beispiel verweist das Attribut app:layoutDescription auf eine Bewegungsszene. Eine Bewegungsszene ist eine XML-Ressourcendatei. Innerhalb ihres <MotionScene>-Stammelements enthält eine Bewegungsszene alle Bewegungsbeschreibungen für das entsprechende Layout. Damit Layoutinformationen von Bewegungsbeschreibungen getrennt bleiben, verweist jedes MotionLayout-Element auf eine separate Bewegungsszene. Die Definitionen in der Bewegungsszene haben Vorrang vor ähnlichen Definitionen in der MotionLayout.

    Hier ist ein Beispiel für eine Bewegungsszenendatei, in der die grundlegende horizontale Bewegung in Abbildung 1 beschrieben wird:

    <?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>
        

    Beachten Sie Folgendes:

    • <Transition> enthält die Basisdefinition der Bewegung.

      • motion:constraintSetStart und motion:constraintSetEnd sind Verweise auf die Endpunkte der Bewegung. Diese Endpunkte werden später in der Bewegungsszene in den <ConstraintSet>-Elementen definiert.

      • motion:duration gibt die Anzahl der Millisekunden an, die für die Ausführung der Bewegung benötigt werden.

    • <OnSwipe> ermöglicht die Touchbedienung der Bewegung.

      • motion:touchAnchorId bezieht sich auf die Ansicht, die der Nutzer wischen und ziehen kann.

      • motion:touchAnchorSide bedeutet, dass die Ansicht von der rechten Seite gezogen wird.

      • motion:dragDirection bezieht sich auf die Fortschritts des Ziehvorgangs. motion:dragDirection="dragRight" bedeutet beispielsweise, dass der Fortschritt zunimmt, wenn die Ansicht nach rechts gezogen wird.

    • In <ConstraintSet> definieren Sie die verschiedenen Einschränkungen, die die Bewegung beschreiben. In diesem Beispiel ist eine <ConstraintSet> für jeden Endpunkt der Bewegung definiert. Diese Endpunkte werden mithilfe von app:layout_constraintTop_toTopOf="parent" und app:layout_constraintBottom_toBottomOf="parent" vertikal zentriert. Horizontal befinden sich die Endpunkte ganz links und rechts auf dem Bildschirm.

    Ausführlichere Informationen zu den verschiedenen Elementen, die von einer Bewegungsszene unterstützt werden, finden Sie in den MotionLayout-Beispielen.

Interpolierte Attribute

Innerhalb einer Bewegungsszenendatei können ConstraintSet-Elemente zusätzliche Attribute enthalten, die während des Übergangs interpoliert werden. Neben Position und Grenzen werden die folgenden Attribute von MotionLayout interpoliert:

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

Benutzerdefinierte Attribute

Innerhalb einer <Constraint> können Sie mit dem Element <CustomAttribute> einen Übergang für Attribute angeben, die nicht nur mit Positions- oder View-Attributen zusammenhängen.

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

Ein <CustomAttribute> enthält zwei eigene Attribute:

  • motion:attributeName ist erforderlich und muss einem Objekt mit Getter- und Setter-Methoden entsprechen. Getter und Setter müssen einem bestimmten Muster entsprechen. Beispielsweise wird backgroundColor unterstützt, da der Ansicht die Methoden getBackgroundColor() und setBackgroundColor() zugrunde liegen.
  • Das andere Attribut, das Sie angeben müssen, hängt vom Werttyp ab. Wählen Sie einen der folgenden unterstützten Typen aus:
    • motion:customColorValue für Farben
    • motion:customIntegerValue für Ganzzahlen
    • motion:customFloatValue für Gleitkommazahlen
    • motion:customStringValue für Strings
    • motion:customDimension für Dimensionen
    • motion:customBoolean für boolesche Werte

Wenn Sie ein benutzerdefiniertes Attribut angeben, definieren Sie Endpunktwerte sowohl im Anfangs- als auch im End-<ConstraintSet>-Element.

Hintergrundfarbe ändern

Nehmen wir ausgehend vom vorherigen Beispiel an, dass sich die Farben der Ansicht im Rahmen der Bewegung ändern sollen (siehe Abbildung 2).

Abbildung 2. Die Hintergrundfarbe der Ansicht ändert sich, während sie sich bewegt.

Fügen Sie jedem ConstraintSet-Element ein <CustomAttribute>-Element hinzu, wie im folgenden Code-Snippet gezeigt:

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

Zusätzliche MotionLayout-Attribute

Zusätzlich zu den Attributen im vorherigen Beispiel gibt es für MotionLayout weitere Attribute, die Sie angeben können:

  • app:applyMotionScene="boolean" gibt an, ob die Bewegungsszene angewendet wird. Der Standardwert für dieses Attribut ist true.
  • app:showPaths="boolean" gibt an, ob die Bewegungspfade während der laufenden Bewegung angezeigt werden sollen. Der Standardwert für dieses Attribut ist false.
  • Mit app:progress="float" können Sie den Übergangsfortschritt explizit angeben. Sie können einen beliebigen Gleitkommawert von 0 (Beginn des Übergangs) bis 1 (Ende des Übergangs) verwenden.
  • Mit app:currentState="reference" können Sie eine bestimmte ConstraintSet angeben.
  • Mit app:motionDebug können Sie zusätzliche Informationen zur Fehlerbehebung zur Bewegung anzeigen lassen. Mögliche Werte sind "SHOW_PROGRESS", "SHOW_PATH" oder "SHOW_ALL".

Weitere Informationen

Weitere Informationen zu MotionLayout finden Sie in den folgenden Ressourcen: