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 Unterklasse von ConstraintLayout und nutzt dessen umfangreiche Layoutfunktionen. Als Teil der ConstraintLayout-Bibliothek ist MotionLayout als Unterstützungsbibliothek verfügbar.

MotionLayout schließt die Lücke zwischen Layoutübergängen und komplexen Bewegungsverarbeitungen und bietet eine Mischung aus Funktionen für das Eigenschaftsanimations-Framework TransitionManager und CoordinatorLayout.

Abbildung 1. Einfache Touchbedienung.

Mit MotionLayout können Sie nicht nur Übergänge zwischen Layouts beschreiben, sondern auch alle Layouteigenschaften animieren. Außerdem werden Suchfunktionen für Übergänge unterstützt. Das bedeutet, dass Sie jeden Punkt innerhalb des Übergangs basierend auf einer Bedingung wie einer Touch-Eingabe sofort anzeigen können. MotionLayout unterstützt auch Keyframes, mit denen sich Übergänge vollständig an Ihre Anforderungen anpassen lassen.

MotionLayout ist vollständig deklarativ, d. h., Sie können beliebige Übergänge in XML beschreiben, unabhängig von ihrer Komplexität.

Designaspekte

MotionLayout dient dazu, UI-Elemente, mit denen Nutzer interagieren, wie Schaltflächen und Titelleisten, zu verschieben, ihre Größe anzupassen und zu animieren. Verwenden Sie in Ihrer App keine Bewegungen als unnötigen Spezialeffekt. Hilf Nutzern dabei, deine App zu verstehen. Weitere Informationen zum Entwerfen Ihrer App mit Bewegung finden Sie im Abschnitt Bewegung verstehen des Artikels zu Material Design.

Erste Schritte

So verwenden Sie MotionLayout in Ihrem Projekt:

  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 Abhängigkeit ConstraintLayout 2.0 hinzu. Wenn Sie AndroidX verwenden, fügen Sie die folgende Abhängigkeit hinzu:

    Groovy

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

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0")
    }
  2. MotionLayout-Datei erstellen:MotionLayout ist eine Unterklasse von ConstraintLayout. Sie können also jede vorhandene ConstraintLayout in eine MotionLayout umwandeln, indem Sie den Klassennamen in Ihrer Layout-Ressourcendatei ersetzen, 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 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 Motion-Szene. Eine Bewegungsszene ist eine XML-Ressourcendatei. Innerhalb des Stammelements <MotionScene> enthält eine Bewegungsszene alle Bewegungsbeschreibungen für das entsprechende Layout. Damit Layoutinformationen von Bewegungsbeschreibungen getrennt bleiben, verweist jedes MotionLayout auf eine separate Bewegungsszene. Die Definitionen in der Bewegungsszene haben Vorrang vor ähnlichen Definitionen in der MotionLayout.

    Hier ist eine Beispieldatei für eine Bewegungsszene, 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>
        

    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 an, wie lange die Bewegung in Millisekunden dauert.

    • Mit <OnSwipe> lassen sich Touchbedienungen für die Bewegung erstellen.

      • motion:touchAnchorId bezieht sich auf die Ansicht, in der Nutzer wischen und ziehen können.

      • motion:touchAnchorSide bedeutet, dass die Ansicht von rechts gezogen wird.

      • motion:dragDirection bezieht sich auf die Vorwärts-Richtung des Ziehens. Beispiel: motion:dragDirection="dragRight" bedeutet, dass der Fortschritt zunimmt, wenn die Ansicht nach rechts gezogen wird.

    • <ConstraintSet> Hier definieren Sie die verschiedenen Einschränkungen, die Ihre Bewegung beschreiben. In diesem Beispiel ist für jeden Endpunkt der Bewegung eine <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.

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

Interpolierte Attribute

In einer Datei mit Bewegungsszenen können ConstraintSet-Elemente zusätzliche Attribute enthalten, die während des Übergangs interpoliert werden. Zusätzlich zu „position“ und „bounds“ werden die folgenden Attribute von MotionLayout interpoliert:

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

Benutzerdefinierte Attribute

Innerhalb eines <Constraint> können Sie mit dem <CustomAttribute>-Element einen Übergang für Attribute angeben, die nicht nur mit der Position 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. backgroundColor wird beispielsweise 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 Floats
    • motion:customStringValue für Strings
    • motion:customDimension für Dimensionen
    • motion:customBoolean für boolesche Werte

Wenn du ein benutzerdefiniertes Attribut angibst, definiere Endpunktwerte in den <ConstraintSet>-Elementen (start und end).

Hintergrundfarbe ändern

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

Abbildung 2. Die Hintergrundfarbe der Ansicht ändert sich beim Bewegen.

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

<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 hat MotionLayout weitere Attribute, die Sie möglicherweise angeben möchten:

  • app:applyMotionScene="boolean" gibt an, ob die Bewegungsszene 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.
  • 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 einen bestimmten ConstraintSet angeben.
  • Mit app:motionDebug können Sie zusätzliche Informationen zur Fehlerbehebung für die Bewegung aufrufen. Mögliche Werte sind "SHOW_PROGRESS", "SHOW_PATH" und "SHOW_ALL".

Weitere Informationen

Weitere Informationen zu MotionLayout finden Sie in den folgenden Ressourcen: