Bewegungen und Widget-Animationen mit MotionLayout verwalten

Jetpack Compose
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Verwenden von Animationen in Compose

MotionLayout ist ein Layouttyp, mit dem Sie Animationen für Bewegungen und Widgets in Ihrer App verwalten können. MotionLayout ist eine abgeleitete Klasse von ConstraintLayout und basiert auf den umfangreichen Layoutfunktionen. Als Teil der ConstraintLayout-Bibliothek ist MotionLayout als Supportbibliothek verfügbar.

MotionLayout schließt die Lücke zwischen Layoutübergängen und komplexer Bewegungsverarbeitung und bietet eine Mischung aus Funktionen des Frameworks für Property-Animationen, TransitionManager und CoordinatorLayout.

Abbildung 1 Grundlegende touchgesteuerte Bewegung

Mit MotionLayout können Sie nicht nur Übergänge zwischen Layouts beschreiben, sondern auch beliebige Layout-Properties animieren. Außerdem werden suchbare Übergänge unterstützt. Das bedeutet, dass Sie basierend auf einer Bedingung, z. B. einer Touch-Eingabe, sofort einen beliebigen Punkt innerhalb des Übergangs anzeigen können. MotionLayout unterstützt auch Keyframes, mit denen Sie Übergänge vollständig an Ihre Anforderungen anpassen können.

MotionLayout ist vollständig deklarativ. Das bedeutet, dass Sie alle Übergänge in XML beschreiben können, unabhängig davon, wie komplex sie sind.

Designaspekte

MotionLayout ist dafür vorgesehen, UI-Elemente, mit denen Nutzer interagieren, z. B. Schaltflächen und Titelleisten, zu verschieben, ihre Größe zu ändern und zu animieren. Verwenden Sie Animationen in Ihrer App nicht als unnötigen Spezialeffekt. Sie sollten Nutzern helfen, zu verstehen, was Ihre App tut. Weitere Informationen zum Designen Ihrer App mit Animationen finden Sie im Abschnitt Animationen im Material Design.

Jetzt starten

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

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

    Cool

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.1"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1"
    }

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
    }
  2. MotionLayout-Datei erstellen: MotionLayout ist eine abgeleitete Klasse von ConstraintLayout. Sie können also jedes vorhandene ConstraintLayout in ein MotionLayout umwandeln, indem Sie den Klassennamen in Ihrer Layoutressourcendatei ersetzen. Das wird 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, die das in Abbildung 1 gezeigte Layout definiert:

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

    Hier ist eine Beispiel-MotionScene-Datei, die die grundlegende horizontale Bewegung in Abbildung 1 beschreibt:

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

    Wichtige Hinweise:

    • <Transition> enthält die grundlegende Definition der Bewegung.

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

      • motion:duration gibt die Anzahl der Millisekunden an, die für die Ausführung der Bewegung erforderlich ist.

    • <OnSwipe> können Sie die Touchbedienung für die Bewegung erstellen.

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

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

      • motion:dragDirection verweist auf die Richtung des Ziehens. Beispiel: motion:dragDirection="dragRight" bedeutet, dass der Fortschritt zunimmt, wenn die Ansicht nach rechts gezogen wird.

    • <ConstraintSet> ist der Ort, an dem Sie die verschiedenen Einschränkungen definieren, die Ihre Bewegung beschreiben. In diesem Beispiel wird für jeden Endpunkt der Bewegung ein <ConstraintSet> definiert. Diese Endpunkte werden mit 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.

    Eine detailliertere Beschreibung der verschiedenen Elemente, die von einer MotionScene unterstützt werden, finden Sie in den MotionLayout-Beispielen.

Interpolierte Attribute

In einer MotionScene-Datei 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, rotationY
  • translationX, translationY, translationZ
  • scaleX, scaleY

Benutzerdefinierte Attribute

In einem <Constraint> können Sie mit dem Element <CustomAttribute> einen Übergang für Attribute angeben, die nicht einfach 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 mit einem Objekt mit Getter- und Setter-Methoden übereinstimmen. Die Getter- und Setter-Methoden müssen einem bestimmten Muster entsprechen. Beispiel: backgroundColor wird unterstützt, da die Ansicht die zugrunde liegenden Methoden getBackgroundColor() und setBackgroundColor() hat.
  • Das andere Attribut, das Sie angeben müssen, basiert auf dem Werttyp. 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 Start- als auch im End <ConstraintSet> Element.

Hintergrundfarbe ändern

Angenommen, Sie möchten, dass sich die Farben der Ansicht im Rahmen der Bewegung ändern, wie in Abbildung 2 gezeigt.

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

Fügen Sie jedem ConstraintSet-Element ein <CustomAttribute>-Element hinzu, wie in dem 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

Neben den Attributen im vorherigen Beispiel hat MotionLayout weitere Attribute, die Sie möglicherweise angeben möchten:

  • app:applyMotionScene="boolean" gibt an, ob die MotionScene angewendet werden soll. Der Standardwert für dieses Attribut ist true.
  • app:showPaths="boolean" gibt an, ob die Bewegungspfade während der Bewegung angezeigt werden sollen. Der Standardwert für dieses Attribut ist false.
  • 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.
  • app:currentState="reference" können Sie ein bestimmtes ConstraintSet angeben.
  • Mit app:motionDebug können Sie zusätzliche Debug-Informationen zur Bewegung anzeigen. Mögliche Werte sind "SHOW_PROGRESS", "SHOW_PATH" oder "SHOW_ALL".

Zusätzliche Ressourcen

Weitere Informationen zu MotionLayout finden Sie in den folgenden Ressourcen: