1. Hinweis
Dieses Codelab ist Teil des Kurses „Advanced Android in Kotlin“. Sie können diesen Kurs am besten nutzen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Das ist jedoch nicht zwingend erforderlich. Alle Codelabs des Kurses sind auf der Landingpage für Codelabs zu Advanced Android in Kotlin aufgeführt.
MotionLayout ist eine Bibliothek, mit der Sie Ihrer Android-App dynamische Animationen hinzufügen können. Sie basiert auf ConstraintLayout, und ermöglicht es Ihnen, alles zu animieren, was Sie mit ConstraintLayout erstellen können.
Mit MotionLayout können Sie die Position, Größe, Sichtbarkeit, den Alphawert, die Farbe, die Höhe, die Drehung und andere Attribute mehrerer Ansichten gleichzeitig animieren. Mit deklarativem XML können Sie koordinierte Animationen mit mehreren Ansichten erstellen, die im Code nur schwer zu realisieren sind.
Animationen sind eine gute Möglichkeit, die Nutzerfreundlichkeit einer App zu verbessern. Mit Animationen können Sie:
- Änderungen anzeigen: Durch Animationen zwischen Status können Nutzer Änderungen in Ihrer Benutzeroberfläche auf natürliche Weise nachvollziehen.
- Aufmerksamkeit erregen: Verwenden Sie Animationen, um die Aufmerksamkeit auf wichtige UI-Elemente zu lenken.
- Ansprechende Designs erstellen: Durch effektive Animationen im Design wirken Apps professioneller.
Vorbereitung
Dieses Codelab richtet sich an Entwickler mit etwas Erfahrung in der Android-Entwicklung. Bevor Sie dieses Codelab durcharbeiten, sollten Sie Folgendes tun:
- Sie wissen, wie Sie mit Android Studio eine App mit einer Aktivität und einem einfachen Layout erstellen und auf einem Gerät oder Emulator ausführen. Sie sollten sich mit
ConstraintLayoutvertraut machen. Weitere Informationen zuConstraintLayoutfinden Sie im Codelab zu ConstraintLayout.
Aufgaben
- Animation mit
ConstraintSetsundMotionLayoutdefinieren - Animation basierend auf Drag-Ereignissen
- Animation mit
KeyPositionändern - Attribute mit
KeyAttributeändern - Animationen mit Code ausführen
- Ein- und ausblendbare Überschriften mit
MotionLayoutanimieren
Voraussetzungen
- Android Studio 4.0 (Der
MotionLayout-Editor funktioniert nur mit dieser Version von Android Studio.)
2. Erste Schritte
So laden Sie die Beispiel-App herunter:
… oder klonen Sie das GitHub-Repository über die Befehlszeile mit dem folgenden Befehl:
$ git clone https://github.com/googlecodelabs/motionlayout.git
3. Animationen mit MotionLayout erstellen
Zuerst erstellen Sie eine Animation, die eine Ansicht als Reaktion auf Nutzerklicks vom oberen Rand des Bildschirms zum unteren Rand verschiebt.
Um eine Animation aus dem Startcode zu erstellen, benötigen Sie die folgenden wichtigen Elemente:
- Eine
MotionLayout,, die eine abgeleitete Klasse vonConstraintLayoutist. Alle Ansichten, die animiert werden sollen, werden imMotionLayout-Tag angegeben. - Eine
MotionScene,, eine XML-Datei, die eine Animation fürMotionLayout.beschreibt - Ein
Transition,, das Teil desMotionSceneist und die Animationsdauer, den Trigger und die Art der Bewegung der Ansichten angibt. - Ein
ConstraintSet, das sowohl die Start- als auch die Ende-Einschränkungen des Übergangs angibt.
Sehen wir uns diese der Reihe nach an, beginnend mit MotionLayout.
Schritt 1: Vorhandenen Code ansehen
MotionLayout ist eine abgeleitete Klasse von ConstraintLayout und unterstützt daher dieselben Funktionen, bietet aber zusätzlich Animationen. Wenn Sie MotionLayout verwenden möchten, fügen Sie eine MotionLayout-Ansicht hinzu, in der Sie ConstraintLayout. verwenden würden.
- Öffnen Sie in
res/layoutdie Dateiactivity_step1.xml.. Sie sehen einConstraintLayoutmit einem einzelnenImageVieweines Sterns, auf den eine Tönung angewendet wurde.
activity_step1.xml
<!-- initial code -->
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/red_star"
...
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Für diese ConstraintLayout gibt es keine Einschränkungen. Wenn Sie die App jetzt ausführen, werden die Sterne also ohne Einschränkungen angezeigt, d. h., sie werden an einer unbekannten Position platziert. Android Studio gibt eine Warnung aus, wenn keine Constraints vorhanden sind.
Schritt 2: In Motion Layout konvertieren
Wenn Sie MotionLayout, für Animationen verwenden möchten, müssen Sie die ConstraintLayout in eine MotionLayout konvertieren.
Damit in Ihrem Layout eine Bewegungsszene verwendet werden kann, muss darauf verwiesen werden.
- Öffnen Sie dazu die Designoberfläche. In Android Studio 4.0 öffnen Sie die Designoberfläche, indem Sie oben rechts das Symbol „Split“ oder „Design“ auswählen, wenn Sie eine Layout-XML-Datei ansehen.

- Klicken Sie nach dem Öffnen der Designoberfläche mit der rechten Maustaste auf die Vorschau und wählen Sie In MotionLayout konvertieren aus.

Dadurch wird das ConstraintLayout-Tag durch ein MotionLayout-Tag ersetzt und dem MotionLayout-Tag wird ein motion:layoutDescription hinzugefügt, das auf @xml/activity_step1_scene. verweist.
activity_step1**.xml**
<!-- explore motion:layoutDescription="@xml/activity_step1_scene" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/activity_step1_scene">
Eine Motion-Szene ist eine einzelne XML-Datei, in der eine Animation in einem MotionLayout beschrieben wird.
Sobald Sie die Umstellung auf MotionLayout vornehmen, wird im Designbereich der Bewegungseditor angezeigt.

Der Motion Editor enthält drei neue Elemente der Benutzeroberfläche:
- Übersicht: In diesem Modal können Sie verschiedene Teile der Animation auswählen. In diesem Bild ist die
startConstraintSetausgewählt. Sie können den Übergang zwischenstartundendauch auswählen, indem Sie auf den Pfeil dazwischen klicken. - Abschnitt: Unter der Übersicht befindet sich ein Abschnittsfenster, das sich je nach dem aktuell ausgewählten Übersichtselement ändert. In diesem Bild werden die Informationen zu
startConstraintSetim Auswahlfenster angezeigt. - Attribut: Im Attributbereich werden die Attribute des aktuell ausgewählten Elements aus dem Übersichts- oder Auswahlfenster angezeigt. Sie können sie dort auch bearbeiten. Auf diesem Bild sind die Attribute für
startConstraintSetzu sehen.
Schritt 3: Start- und Endbedingungen definieren
Alle Animationen können durch einen Start und ein Ende definiert werden. Der Start beschreibt, wie der Bildschirm vor der Animation aussieht, und das Ende, wie er nach Abschluss der Animation aussieht. MotionLayout ist dafür verantwortlich, wie die Animation zwischen dem Start- und dem Endstatus (im Zeitverlauf) erfolgt.
MotionScene verwendet ein ConstraintSet-Tag, um die Start- und Endstatus zu definieren. Ein ConstraintSet ist genau das, was der Name vermuten lässt: eine Reihe von Einschränkungen, die auf Ansichten angewendet werden können. Dazu gehören Breiten-, Höhen- und ConstraintLayout-Einschränkungen. Dazu gehören auch einige Attribute wie alpha. Sie enthält nicht die Ansichten selbst, sondern nur die Einschränkungen für diese Ansichten.
Alle in einer ConstraintSet-Datei angegebenen Einschränkungen überschreiben die in der Layoutdatei angegebenen Einschränkungen. Wenn Sie Einschränkungen sowohl im Layout als auch in der MotionScene definieren, werden nur die Einschränkungen in der MotionScene angewendet.
In diesem Schritt beschränken Sie die Sternenansicht so, dass sie oben auf dem Bildschirm beginnt und unten auf dem Bildschirm endet.
Sie können diesen Schritt entweder mit dem Motion Editor oder durch direktes Bearbeiten des Texts von activity_step1_scene.xml ausführen.
- Wählen Sie im Übersichtsfeld das
startConstraintSet aus.

- Wählen Sie im Bereich Auswahl die Option
red_staraus. Derzeit wird „Quelle vonlayout“ angezeigt. Das bedeutet, dass die Quelle in dieserConstraintSetnicht eingeschränkt ist. Klicken Sie oben rechts auf das Stiftsymbol, um eine Einschränkung zu erstellen.

- Prüfen Sie, ob für
red_stardie Quellestartangezeigt wird, wenn im ÜbersichtsbereichstartConstraintSetausgewählt ist. - Fügen Sie im Bereich „Attribute“ mit
red_starin derstartConstraintSeteine Einschränkung oben hinzu. Klicken Sie dazu zuerst auf die blauen Schaltflächen +.

- Öffnen Sie
xml/activity_step1_scene.xml, um den Code zu sehen, den der Motion Editor für diese Einschränkung generiert hat.
activity_step1_scene.xml
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
Das ConstraintSet hat ein id von @id/start und gibt alle Einschränkungen an, die auf alle Ansichten im MotionLayout angewendet werden sollen. Da diese MotionLayout nur eine Datenansicht hat, ist nur ein Constraint erforderlich.
Die Constraint in ConstraintSet gibt die ID der Ansicht an, die eingeschränkt wird, @id/red_star, die in activity_step1.xml definiert ist. Constraint-Tags geben nur Einschränkungen und Layoutinformationen an. Das Constraint-Tag weiß nicht, dass es auf ein ImageView angewendet wird.
Diese Einschränkung gibt die Höhe, Breite und die beiden anderen Einschränkungen an, die erforderlich sind, um die red_star-Ansicht auf den oberen Anfang des übergeordneten Elements zu beschränken.
- Wählen Sie im Übersichtsbereich das
endConstraintSet aus.

- Führen Sie dieselben Schritte wie zuvor aus, um dem
endConstraintSeteineConstraintfürred_starhinzuzufügen. - Wenn Sie den Motion Editor für diesen Schritt verwenden möchten, fügen Sie dem
bottomund demendeine Einschränkung hinzu, indem Sie auf die blauen +-Schaltflächen klicken.

- Der Code in XML sieht so aus:
activitiy_step1_scene.xml
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
Wie bei @id/start hat dieses ConstraintSet ein einzelnes Constraint auf @id/red_star. Dieses Mal wird es auf den unteren Bildschirmrand beschränkt.
Sie müssen sie nicht @id/start und @id/end nennen, aber es ist praktisch, dies zu tun.
Schritt 4: Übergang definieren
Jede MotionScene muss außerdem mindestens einen Übergang enthalten. Eine Übergangsanimation definiert jeden Teil einer Animation, vom Anfang bis zum Ende.
Für einen Übergang muss ein Start- und End-ConstraintSet angegeben werden. Mit einem Übergang kann auch angegeben werden, wie die Animation auf andere Weise geändert werden soll, z. B. wie lange sie ausgeführt werden soll oder wie Ansichten durch Ziehen animiert werden sollen.
- Motion Editor hat beim Erstellen der MotionScene-Datei standardmäßig eine Übergangsanimation für uns erstellt. Öffnen Sie
activity_step1_scene.xml, um den generierten Übergang zu sehen.
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
Das ist alles, was MotionLayout zum Erstellen einer Animation benötigt. Sehen wir uns die einzelnen Attribute an:
constraintSetStartwird auf die Aufrufe angewendet, sobald die Animation beginnt.constraintSetEndwird auf die Ansichten am Ende der Animation angewendet.durationgibt an, wie lange die Animation in Millisekunden dauern soll.
MotionLayout berechnet dann einen Pfad zwischen den Start- und Endbedingungen und animiert ihn für die angegebene Dauer.
Schritt 5: Vorschau der Animation im Motion Editor ansehen

Animation:Video, in dem eine Übergangsvorschau im Motion Editor wiedergegeben wird
- Öffnen Sie den Motion Editor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen
startundendklicken.

- Im Bereich Auswahl werden Wiedergabesteuerelemente und eine Scrubbing-Leiste angezeigt, wenn eine Übergang ausgewählt ist. Klicken Sie auf „Wiedergabe“ oder ziehen Sie die aktuelle Position, um sich die Animation anzusehen.

Schritt 6: On-Click-Handler hinzufügen
Sie benötigen eine Möglichkeit, die Animation zu starten. Eine Möglichkeit hierfür ist, das MotionLayout auf Click-Events auf @id/red_star reagieren zu lassen.
- Öffnen Sie den Bewegungseditor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen Start und Ende klicken.

- Klicken Sie in der Symbolleiste für das Übersichtspanel auf
Klick- oder Wisch-Handler erstellen . Dadurch wird ein Handler hinzugefügt, der einen Übergang startet. - Wählen Sie im Pop-up-Fenster Klick-Handler aus.

- Ändern Sie Ansicht zum Klicken in
red_star.

- Klicken Sie auf Hinzufügen. Der Click-Handler wird im Bewegungseditor durch einen kleinen Punkt auf dem Übergang dargestellt.

- Fügen Sie dem OnClick-Handler, den Sie gerade im Attributbereich hinzugefügt haben, ein
clickAction-Attribut mit dem Werttogglehinzu.

- Öffnen Sie
activity_step1_scene.xml, um den vom Motion Editor generierten Code zu sehen.
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/red_star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
Mit dem Transition-Tag wird MotionLayout angewiesen, die Animation als Reaktion auf Klickereignisse mit einem <OnClick>-Tag auszuführen. Sehen wir uns die einzelnen Attribute an:
targetIdist die Ansicht, in der Sie nach Klicks suchen müssen.clickActionvontogglewechselt bei einem Klick zwischen dem Start- und dem Endzustand. Weitere Optionen fürclickAction
- Führen Sie den Code aus, klicken Sie auf Schritt 1 und dann auf den roten Stern, um die Animation zu sehen.
Schritt 5: Animationen in Aktion
Führen Sie die App aus. Wenn Sie auf den Stern klicken, sollte die Animation abgespielt werden.

Die Datei mit der abgeschlossenen Bewegungsszene definiert einen Transition, der auf einen Start- und End-ConstraintSet verweist.
Zu Beginn der Animation (@id/start) ist das Sternsymbol an der oberen linken Ecke des Bildschirms fixiert. Am Ende der Animation (@id/end) ist das Sternsymbol am unteren Rand des Bildschirms fixiert.
<?xml version="1.0" encoding="utf-8"?>
<!-- Describe the animation for activity_step1.xml -->
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
</MotionScene>
4. Animationen basierend auf Drag-Ereignissen
In diesem Schritt erstellen Sie eine Animation, die auf ein Drag-Ereignis des Nutzers (wenn der Nutzer über den Bildschirm wischt) reagiert, um die Animation auszuführen. MotionLayout unterstützt das Erfassen von Touch-Ereignissen zum Verschieben von Ansichten sowie physikbasierte Wischbewegungen, um die Bewegung flüssig zu gestalten.
Schritt 1: Ursprünglichen Code prüfen
- Öffnen Sie dazu die Layoutdatei
activity_step2.xml, die bereits einMotionLayoutenthält. Sehen Sie sich den Code an.
activity_step2.xml
<!-- initial code -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/step2" >
<ImageView
android:id="@+id/left_star"
...
/>
<ImageView
android:id="@+id/right_star"
...
/>
<ImageView
android:id="@+id/red_star"
...
/>
<TextView
android:id="@+id/credits"
...
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
In diesem Layout werden alle Ansichten für die Animation definiert. Die drei Sternsymbole sind im Layout nicht eingeschränkt, da sie in der Bewegungsszene animiert werden.
Für die Credits TextView gelten Einschränkungen, da sie während der gesamten Animation an derselben Stelle bleiben und keine Attribute geändert werden.
Schritt 2: Szene animieren
Wie bei der letzten Animation wird die Animation durch einen Start- und einen End-ConstraintSet, und ein Transition definiert.
Definieren Sie das ConstraintSet für den Start.
- Öffnen Sie die Bewegungsszene
xml/step2.xml, um die Animation zu definieren. - Fügen Sie die Einschränkungen für die Startbedingung
starthinzu. Zu Beginn sind alle drei Sterne unten in der Mitte des Bildschirms zu sehen. Die Sterne rechts und links haben denalpha-Wert0.0. Das bedeutet, dass sie vollständig transparent und ausgeblendet sind.
step2.xml
<!-- TODO apply starting constraints -->
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
In diesem ConstraintSet geben Sie für jeden Stern ein Constraint an. Jede Einschränkung wird von MotionLayout zu Beginn der Animation angewendet.
Jede Sternansicht wird mithilfe von Start-, End- und unteren Einschränkungen unten auf dem Bildschirm zentriert. Die beiden Sterne @id/left_star und @id/right_star haben beide einen zusätzlichen Alphawert, der sie unsichtbar macht und der zu Beginn der Animation angewendet wird.
Die Einschränkungssätze start und end definieren den Anfang und das Ende der Animation. Eine Einschränkung für den Start, z. B. motion:layout_constraintStart_toStartOf, legt den Start einer Ansicht auf den Start einer anderen Ansicht fest. Das kann anfangs verwirrend sein, da der Name start sowohl für als auch für verwendet wird und beide im Kontext von Einschränkungen verwendet werden. Um die Unterscheidung zu verdeutlichen, bezieht sich start in layout_constraintStart auf den „Start“ der Ansicht, also links bei linksläufigen Sprachen und rechts bei rechtsläufigen Sprachen. Der start-Einschränkungssatz bezieht sich auf den Beginn der Animation.
End-ConstraintSet definieren
- Definieren Sie die Endbeschränkung, um alle drei Sterne mit einer Kette unter
@id/creditszu positionieren. Außerdem wird der Endwert vonalphader linken und rechten Sterne auf1.0gesetzt.
step2.xml
<!-- TODO apply ending constraints -->
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintHorizontal_chainStyle="packed"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toStartOf="@id/red_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@id/left_star"
motion:layout_constraintEnd_toStartOf="@id/right_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintStart_toEndOf="@id/red_star"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@id/credits" />
</ConstraintSet>
Das Ergebnis ist, dass sich die Ansichten beim Animieren vom Zentrum aus nach außen und oben ausbreiten.
Da die alpha-Property in beiden ConstraintSets für @id/right_start und @id/left_star festgelegt ist, werden beide Ansichten im Laufe der Animation eingeblendet.
Animation basierend auf dem Wischen des Nutzers
Mit MotionLayout können Nutzer-Drag-Ereignisse oder ein Wischen erfasst werden, um eine physikbasierte „Schleuder“-Animation zu erstellen. Das bedeutet, dass die Ansichten weiterlaufen, wenn der Nutzer sie schleudert, und sich verlangsamen, wie es bei einem physischen Objekt der Fall wäre, das über eine Oberfläche rollt. Sie können diese Art von Animation mit einem OnSwipe-Tag im Transition hinzufügen.
- Ersetzen Sie das TODO für das Hinzufügen eines
OnSwipe-Tags durch<OnSwipe motion:touchAnchorId="@id/red_star" />.
step2.xml
<!-- TODO add OnSwipe tag -->
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end">
<!-- MotionLayout will track swipes relative to this view -->
<OnSwipe motion:touchAnchorId="@id/red_star" />
</Transition>
OnSwipe enthält einige Attribute, wobei touchAnchorId das wichtigste ist.
touchAnchorIdist die verfolgte Ansicht, die sich als Reaktion auf Berührungen bewegt.MotionLayouthält diese Ansicht auf demselben Abstand zum Finger, der wischt.- Mit
touchAnchorSidewird festgelegt, welche Seite der Ansicht erfasst werden soll. Das ist wichtig für Ansichten, die ihre Größe ändern, komplexen Pfaden folgen oder bei denen sich eine Seite schneller bewegt als die andere. dragDirectionbestimmt, welche Richtung für diese Animation wichtig ist (oben, unten, links oder rechts).
Wenn MotionLayout auf Ziehereignisse wartet, wird der Listener für die MotionLayout-Ansicht und nicht für die von touchAnchorId angegebene Ansicht registriert. Wenn ein Nutzer eine Geste an einer beliebigen Stelle auf dem Bildschirm beginnt, hält MotionLayout den Abstand zwischen seinem Finger und dem touchAnchorSide der touchAnchorId-Ansicht konstant. Wenn sie beispielsweise 100 dp von der Ankerseite entfernt sind, hält MotionLayout diese Seite während der gesamten Animation 100 dp von ihrem Finger entfernt.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und öffnen Sie den Bildschirm „Schritt 2“. Die Animation wird angezeigt.
- Probieren Sie aus, Ihren Finger während der Animation loszulassen, um zu sehen, wie
MotionLayoutflüssigkeitsbasierte Animationen darstellt.

Mit MotionLayout lassen sich sehr unterschiedliche Designs animieren. Dabei können Sie die Funktionen von ConstraintLayout nutzen, um ansprechende Effekte zu erzielen.
In dieser Animation sind alle drei Ansichten zu Beginn relativ zu ihrem übergeordneten Element unten auf dem Bildschirm positioniert. Am Ende werden die drei Ansichten relativ zu @id/credits in einer Kette positioniert.
Trotz dieser sehr unterschiedlichen Layouts wird mit MotionLayout eine flüssige Animation zwischen Start und Ende erstellt.
5. Pfad ändern
In diesem Schritt erstellen Sie eine Animation, die einem komplexen Pfad folgt und die Credits während der Bewegung animiert. Mit MotionLayout kann der Pfad geändert werden, den eine Ansicht zwischen dem Start und dem Ende nimmt. Dazu wird ein KeyPosition verwendet.
Schritt 1: Vorhandenen Code ansehen
- Öffnen Sie
layout/activity_step3.xmlundxml/step3.xml, um das vorhandene Layout und die Bewegungsszene zu sehen. InImageViewundTextViewwerden der Mond und der Abspanntext angezeigt. - Öffnen Sie die Datei mit der Bewegungsszene (
xml/step3.xml). Sie sehen, dass einTransitionvon@id/startnach@id/enddefiniert ist. In der Animation wird das Mondbild mit zweiConstraintSetsvon links unten nach rechts unten auf dem Bildschirm verschoben. Der Abspanntext wird vonalpha="0.0"bisalpha="1.0"eingeblendet, während sich der Mond bewegt. - Führen Sie die App jetzt aus und wählen Sie Schritt 3 aus. Wenn Sie auf den Mond klicken, sehen Sie, dass er einem linearen Pfad (oder einer geraden Linie) vom Start bis zum Ende folgt.
Schritt 2: Pfad-Debugging aktivieren
Bevor Sie der Bewegung des Mondes einen Bogen hinzufügen, sollten Sie das Pfad-Debugging in MotionLayout aktivieren.
Um komplexe Animationen mit MotionLayout zu entwickeln, können Sie den Animationspfad jeder Ansicht zeichnen. Das ist hilfreich, wenn Sie Ihre Animation visualisieren und die kleinen Details der Bewegung optimieren möchten.
- Wenn Sie Debugging-Pfade aktivieren möchten, öffnen Sie
layout/activity_step3.xmlund fügen Sie demMotionLayout-Tagmotion:motionDebug="SHOW_PATH"hinzu.
activity_step3.xml
<!-- Add motion:motionDebug="SHOW_PATH" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:motionDebug="SHOW_PATH" >
Wenn Sie das Pfad-Debugging aktiviert haben und die App noch einmal ausführen, werden die Pfade aller Ansichten mit einer gepunkteten Linie visualisiert.

- Kreise stellen die Start- oder Endposition einer Ansicht dar.
- Linien stellen den Pfad einer Ansicht dar.
- Rauten stellen einen
KeyPositiondar, der den Pfad ändert.
In dieser Animation ist der mittlere Kreis beispielsweise die Position des Abspanntexts.
Schritt 3: Pfad ändern
Alle Animationen in MotionLayout werden durch einen Start- und einen Endpunkt ConstraintSet definiert, der festlegt, wie der Bildschirm vor Beginn und nach Abschluss der Animation aussieht. Standardmäßig wird mit MotionLayout ein linearer Pfad (eine gerade Linie) zwischen der Start- und der Endposition jeder Ansicht gezeichnet, deren Position sich ändert.
Um komplexe Pfade wie den Bogen des Mondes in diesem Beispiel zu erstellen, verwendet MotionLayout ein KeyPosition, um den Pfad zu ändern, den eine Ansicht zwischen Start und Ende nimmt.
- Öffnen Sie
xml/step3.xmlund fügen Sie der Szene einKeyPositionhinzu. DasKeyPosition-Tag wird innerhalb desTransition-Tags platziert.

step3.xml
<!-- TODO: Add KeyFrameSet and KeyPosition -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
Ein KeyFrameSet ist ein untergeordnetes Element eines Transition und eine Gruppe aller KeyFrames, z. B. KeyPosition, die während des Übergangs angewendet werden sollen.
Da MotionLayout den Pfad für den Mond zwischen dem Start und dem Ende berechnet, wird der Pfad basierend auf dem in KeyFrameSet angegebenen KeyPosition geändert. Wenn Sie die App noch einmal ausführen, sehen Sie, wie sich der Pfad ändert.
Ein KeyPosition-Objekt hat mehrere Attribute, die beschreiben, wie der Pfad geändert wird. Die wichtigsten sind:
framePositionist eine Zahl zwischen 0 und 100. Damit wird definiert, wann dieserKeyPositionin der Animation angewendet werden soll. Der Wert 1 entspricht 1% der Animation und der Wert 99 entspricht 99% der Animation. Wenn der Wert also 50 ist, wird er genau in der Mitte angewendet.motionTargetist die Ansicht, für die mit diesemKeyPositionder Pfad geändert wird.keyPositionTypezeigt, wie der Pfad durchKeyPositiongeändert wird. Er kann entwederparentRelative,pathRelativeoderdeltaRelativesein (wie im nächsten Schritt erläutert).percentX | percentYgibt an, wie stark der Pfad beiframePositiongeändert werden soll (Werte zwischen 0,0 und 1,0, wobei negative Werte und Werte > 1 zulässig sind).
Sie können sich das so vorstellen: „Ändere bei framePosition den Pfad von motionTarget durch Verschieben um percentX oder percentY entsprechend den von keyPositionTypeermittelten Koordinaten.“
Standardmäßig werden alle Ecken, die durch das Ändern des Pfads entstehen, durch MotionLayout abgerundet. Wenn Sie sich die gerade erstellte Animation ansehen, können Sie erkennen, dass der Mond in der Kurve einem gekrümmten Pfad folgt. In den meisten Fällen ist das auch gewünscht. Andernfalls können Sie das Attribut curveFit angeben, um die Animation anzupassen.
Jetzt ausprobieren
Wenn Sie die App noch einmal ausführen, wird die Animation für diesen Schritt angezeigt.

Der Mond folgt einem Bogen, da er einen in der Transition angegebenen KeyPosition durchläuft.
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
Sie können KeyPosition so lesen: „Ändere bei framePosition 50 (auf halbem Weg durch die Animation) den Pfad von motionTarget @id/moon, indem du ihn um 50% Y (auf halbem Weg nach unten auf dem Bildschirm) entsprechend den Koordinaten verschiebst, die durch parentRelative (die gesamte MotionLayout) bestimmt werden.“
In der Mitte der Animation muss der Mond also durch einen KeyPosition gehen, der 50% unter dem oberen Bildschirmrand liegt. Diese KeyPosition ändert die X-Bewegung überhaupt nicht. Der Mond bewegt sich also weiterhin horizontal von Anfang bis Ende. MotionLayout berechnet einen glatten Pfad, der durch diesen KeyPosition verläuft, während er sich zwischen Start und Ende bewegt.
Wenn Sie genau hinsehen, wird der Text für die Credits durch die Position des Mondes eingeschränkt. Warum bewegt es sich nicht auch vertikal?

<Constraint
android:id="@id/credits"
...
motion:layout_constraintBottom_toBottomOf="@id/moon"
motion:layout_constraintTop_toTopOf="@id/moon"
/>
Obwohl du den Pfad des Mondes änderst, bewegen sich die Start- und Endpositionen des Mondes vertikal überhaupt nicht. KeyPosition ändert die Start- oder Endposition nicht, sodass der Abspanntext auf die endgültige Endposition des Mondes beschränkt ist.
Wenn Sie möchten, dass sich der Abspann mit dem Mond bewegt, können Sie dem Abspann ein KeyPosition hinzufügen oder die Startbedingungen für @id/credits ändern.
Im nächsten Abschnitt werden die verschiedenen Arten von keyPositionType in MotionLayout beschrieben.
6. keyPositionType
Im letzten Schritt haben Sie den keyPosition-Typ parentRelative verwendet, um den Pfad um 50% des Bildschirms zu versetzen. Das Attribut keyPositionType bestimmt, wie MotionLayout den Pfad gemäß percentX oder percentY ändert.
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
Es gibt drei verschiedene Arten von keyPosition: parentRelative, pathRelative und deltaRelative. Wenn Sie einen Typ angeben, ändert sich das Koordinatensystem, anhand dessen percentX und percentY berechnet werden.
Was ist ein Koordinatensystem?
Ein Koordinatensystem bietet eine Möglichkeit, einen Punkt im Raum anzugeben. Sie sind auch nützlich, um eine Position auf dem Bildschirm zu beschreiben.
MotionLayout-Koordinatensysteme sind kartesische Koordinatensysteme. Das bedeutet, dass sie eine X- und eine Y-Achse haben, die durch zwei senkrechte Linien definiert werden. Der Hauptunterschied zwischen den beiden besteht darin, wo sich die X-Achse auf dem Bildschirm befindet (die Y-Achse verläuft immer senkrecht zur X-Achse).
Alle Koordinatensysteme in MotionLayout verwenden Werte zwischen 0.0 und 1.0 auf der X- und der Y-Achse. Sie lassen negative Werte und Werte zu, die größer als 1.0 sind. Ein percentX-Wert von -2.0 würde beispielsweise bedeuten, dass Sie sich zweimal in die entgegengesetzte Richtung der X-Achse bewegen.
Wenn sich das alles ein bisschen zu sehr nach Algebraunterricht anhört, sehen Sie sich die Bilder unten an.
parentRelative-Koordinaten

Die keyPositionType von parentRelative verwendet dasselbe Koordinatensystem wie der Bildschirm. Dabei wird (0, 0) oben links und (1, 1) unten rechts im gesamten MotionLayout definiert.
Sie können parentRelative verwenden, wenn Sie eine Animation erstellen möchten, die sich über den gesamten MotionLayout erstreckt, wie der Mondbogen in diesem Beispiel.
Wenn Sie einen Pfad jedoch relativ zur Bewegung ändern möchten, z. B. ihn leicht krümmen, sind die anderen beiden Koordinatensysteme besser geeignet.
deltaRelative-Koordinaten

Delta ist ein mathematischer Begriff für Änderung. deltaRelative bedeutet also „relative Änderung“. In deltaRelative-Koordinaten(0,0) ist die Startposition der Ansicht und (1,1) die Endposition. Die X- und Y-Achsen sind am Bildschirm ausgerichtet.
Die X-Achse ist immer horizontal auf dem Bildschirm und die Y-Achse immer vertikal. Im Vergleich zu parentRelative besteht der Hauptunterschied darin, dass die Koordinaten nur den Teil des Bildschirms beschreiben, in dem sich die Ansicht bewegt.
deltaRelative ist ein hervorragendes Koordinatensystem, um die horizontale oder vertikale Bewegung isoliert zu steuern. Sie könnten beispielsweise eine Animation erstellen, bei der die vertikale (Y-)Bewegung bei 50 % abgeschlossen ist und die horizontale (X-)Bewegung fortgesetzt wird.
Pfadrelative Koordinaten

Das letzte Koordinatensystem in MotionLayout ist pathRelative. Sie unterscheidet sich deutlich von den anderen beiden, da die X-Achse dem Bewegungspfad vom Start bis zum Ende folgt. (0,0) ist also die Startposition und (1,0) die Endposition.
Warum sollten Sie das tun? Das ist auf den ersten Blick ziemlich überraschend, zumal dieses Koordinatensystem nicht einmal am Bildschirmkoordinatensystem ausgerichtet ist.
pathRelative ist für einige Dinge wirklich nützlich.
- Ansicht während eines Teils der Animation beschleunigen, verlangsamen oder anhalten: Da die X-Dimension immer genau dem Pfad entspricht, den die Ansicht nimmt, können Sie mit
pathRelativeKeyPositionändern, bei welchemframePositionein bestimmter Punkt auf diesem Pfad erreicht wird. Bei einemKeyPositionbeiframePosition="50"mit einempercentX="0.1"würde die Animation für die ersten 10% der Bewegung 50% der Zeit benötigen. - Einem Pfad einen subtilen Bogen hinzufügen Da die Y-Dimension immer senkrecht zur Bewegung verläuft, wird durch Ändern von Y der Pfad relativ zur Gesamtbewegung gekrümmt.
- Eine zweite Dimension hinzufügen
deltaRelativefunktioniert nicht. Bei rein horizontalen und vertikalen Bewegungen wird mitdeltaRelativenur eine nützliche Dimension erstellt.pathRelativeerstellt jedoch immer nutzbare X- und Y-Koordinaten.
Im nächsten Schritt erfahren Sie, wie Sie noch komplexere Pfade mit mehr als einem KeyPosition erstellen.
7. Komplexe Pfade erstellen
Die Animation, die Sie im letzten Schritt erstellt haben, hat eine glatte Kurve, aber die Form könnte eher wie ein Mond aussehen.
Pfad mit mehreren KeyPosition-Elementen ändern
Mit MotionLayout kann ein Pfad weiter angepasst werden, indem beliebig viele KeyPosition definiert werden, um eine beliebige Bewegung zu erzielen. Für diese Animation erstellen Sie einen Bogen. Sie könnten den Mond aber auch in der Mitte des Bildschirms auf und ab springen lassen.
- Öffnen Sie
xml/step4.xml. Es hat dieselben Aufrufe und dieKeyFrame, die Sie im letzten Schritt hinzugefügt haben. - Um die Spitze der Kurve abzurunden, fügen Sie dem Pfad von
@id/moonzwei weitereKeyPositionshinzu, eine kurz vor und eine kurz nach dem Erreichen des höchsten Punkts.

step4.xml
<!-- TODO: Add two more KeyPositions to the KeyFrameSet here -->
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
Diese KeyPositions werden bei 25% und 75% der Animation angewendet. Dadurch bewegt sich @id/moon auf einem Pfad, der 60% vom oberen Bildschirmrand entfernt ist. In Kombination mit der vorhandenen KeyPosition von 50 % ergibt sich ein sanfter Bogen für die Bewegung des Mondes.
In MotionLayout können Sie so viele KeyPositions hinzufügen, wie Sie für den gewünschten Bewegungspfad benötigen. MotionLayout wendet jedes KeyPosition am angegebenen framePosition an und ermittelt, wie eine flüssige Bewegung durch alle KeyPositions erstellt werden kann.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus. Schritt 4 zeigt die Animation in Aktion. Wenn Sie auf den Mond klicken, folgt er dem Pfad vom Start bis zum Ende und durchläuft dabei jedes
KeyPosition, das in derKeyFrameSetangegeben wurde.
Selbst erkunden
Bevor Sie sich anderen Arten von KeyFrame zuwenden, sollten Sie dem KeyFrameSet einige weitere KeyPositions hinzufügen, um zu sehen, welche Effekte Sie nur mit KeyPosition erzielen können.
Hier ist ein Beispiel für das Erstellen eines komplexen Pfads, der sich während der Animation hin und her bewegt.

step4.xml
<!-- Complex paths example: Dancing moon -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
motion:percentX="0.3"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
</KeyFrameSet>
Wenn Sie KeyPosition fertig erkundet haben, geht es im nächsten Schritt mit anderen Arten von KeyFrames weiter.
8. Attribute während der Bewegung ändern
Beim Erstellen dynamischer Animationen werden häufig die size-, rotation- oder alpha-Werte von Ansichten im Laufe der Animation geändert. Mit MotionLayout lassen sich viele Attribute in einer beliebigen Ansicht mit einem KeyAttribute animieren.
In diesem Schritt verwenden Sie KeyAttribute, um den Mond zu skalieren und zu drehen. Außerdem verwenden Sie ein KeyAttribute, um die Anzeige des Texts zu verzögern, bis der Mond seine Reise fast abgeschlossen hat.
Schritt 1: Größe und Drehung mit KeyAttribute anpassen
- Öffnen Sie
xml/step5.xml, die dieselbe Animation enthält, die Sie im letzten Schritt erstellt haben. Auf diesem Bildschirm wird zur Abwechslung ein anderes Weltraumbild als Hintergrund verwendet. - Damit sich der Mond vergrößert und dreht, fügen Sie zwei
KeyAttribute-Tags inKeyFrameSetbeikeyFrame="50"undkeyFrame="100"ein.

step5.xml
<!-- TODO: Add KeyAttributes to rotate and resize @id/moon -->
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon"
android:scaleY="2.0"
android:scaleX="2.0"
android:rotation="-360"
/>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon"
android:rotation="-720"
/>
Diese KeyAttributes werden bei 50% und 100% der Animation angewendet. Die erste KeyAttribute bei 50% erfolgt am oberen Ende des Bogens. Dadurch wird die Ansicht verdoppelt und um -360 Grad (oder einen vollen Kreis) gedreht. Mit dem zweiten KeyAttribute wird die zweite Drehung auf -720 Grad (zwei volle Kreise) abgeschlossen und die Größe wird wieder auf den regulären Wert verkleinert, da die Werte scaleX und scaleY standardmäßig auf 1,0 festgelegt sind.
Wie bei einem KeyPosition werden bei einem KeyAttribute die framePosition und motionTarget verwendet, um anzugeben, wann die KeyFrame angewendet werden soll und welche Ansicht geändert werden soll. MotionLayout interpoliert zwischen KeyPositions, um flüssige Animationen zu erstellen.
KeyAttributes unterstützt Attribute, die auf alle Ansichten angewendet werden können. Sie unterstützen das Ändern von grundlegenden Attributen wie visibility, alpha oder elevation. Sie können die Drehung auch wie hier ändern, mit rotateX und rotateY in drei Dimensionen drehen, mit scaleX und scaleY die Größe skalieren oder die Position der Ansicht in X, Y oder Z verschieben.
Schritt 2: Abspann verzögern
Ziel dieses Schritts ist es, die Animation so zu aktualisieren, dass der Abspanntext erst erscheint, wenn die Animation fast abgeschlossen ist.
- Wenn Sie die Anzeige des Abspanns verzögern möchten, definieren Sie einen weiteren
KeyAttribute, der dafür sorgt, dassalphabiskeyPosition="85"auf 0 bleibt.MotionLayoutwird weiterhin reibungslos von 0 auf 100 % Alpha übergehen, allerdings erst in den letzten 15 % der Animation.
step5.xml
<!-- TODO: Add KeyAttribute to delay the appearance of @id/credits -->
<KeyAttribute
motion:framePosition="85"
motion:motionTarget="@id/credits"
android:alpha="0.0"
/>
Durch dieses KeyAttribute bleibt der alpha von @id/credits für die ersten 85% der Animation bei 0,0. Da der Alphawert am Anfang 0 ist, ist das Element in den ersten 85% der Animation nicht sichtbar.
Das Ergebnis dieser KeyAttribute ist, dass der Abspann gegen Ende der Animation angezeigt wird. Dadurch entsteht der Eindruck, dass sie mit dem Mond koordiniert sind, der sich in der rechten Ecke des Bildschirms niederlässt.
Wenn Sie Animationen in einer Ansicht verzögern, während sich eine andere Ansicht so bewegt, können Sie beeindruckende Animationen erstellen, die sich für den Nutzer dynamisch anfühlen.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und gehen Sie zu Schritt 5, um die Animation in Aktion zu sehen. Wenn Sie auf den Mond klicken, folgt er dem Pfad vom Start bis zum Ende und durchläuft dabei alle
KeyAttribute, die in derKeyFrameSetangegeben wurden.

Da Sie den Mond zweimal um die eigene Achse drehen, macht er nun einen doppelten Rückwärtssalto. Die Credits werden erst eingeblendet, wenn die Animation fast abgeschlossen ist.
Selbst erkunden
Bevor Sie mit dem letzten Typ von KeyFrame fortfahren, sollten Sie andere Standard-Attribute in der KeyAttributes ändern. Ändern Sie beispielsweise rotation in rotationX, um zu sehen, welche Animation dadurch erstellt wird.
Hier ist eine Liste der Standardattribute, die Sie ausprobieren können:
android:visibilityandroid:alphaandroid:elevationandroid:rotationandroid:rotationXandroid:rotationYandroid:scaleXandroid:scaleYandroid:translationXandroid:translationYandroid:translationZ
9. Benutzerdefinierte Attribute ändern
Bei umfangreichen Animationen werden die Farbe oder andere Attribute einer Ansicht geändert. Während MotionLayout ein KeyAttribute verwenden kann, um eines der Standardattribute zu ändern, die in der vorherigen Aufgabe aufgeführt sind, verwenden Sie ein CustomAttribute, um ein beliebiges anderes Attribut anzugeben.
Mit einem CustomAttribute kann jeder Wert festgelegt werden, für den ein Setter vorhanden ist. Sie können beispielsweise die backgroundColor einer View mit einem CustomAttribute festlegen. MotionLayout verwendet reflection, um den Setter zu finden, und ruft ihn dann wiederholt auf, um die Ansicht zu animieren.
In diesem Schritt verwenden Sie ein CustomAttribute, um das Attribut colorFilter für den Mond festzulegen und die unten gezeigte Animation zu erstellen.

Benutzerdefinierte Attribute definieren
- Öffnen Sie zuerst
xml/step6.xml. Sie enthält dieselbe Animation, die Sie im letzten Schritt erstellt haben. - Damit der Mond die Farbe ändert, füge zwei
KeyAttributemit einemCustomAttributeimKeyFrameSetbeikeyFrame="0",keyFrame="50"undkeyFrame="100".ein.

step6.xml
<!-- TODO: Add Custom attributes here -->
<KeyAttribute
motion:framePosition="0"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFB612"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
Sie fügen ein CustomAttribute in ein KeyAttribute ein. Die CustomAttribute wird am framePosition angewendet, der von der KeyAttribute angegeben wird.
Im CustomAttribute müssen Sie eine attributeName und einen festzulegenden Wert angeben.
motion:attributeNameist der Name des Setters, der von diesem benutzerdefinierten Attribut aufgerufen wird. In diesem Beispiel wirdsetColorFilterfürDrawableaufgerufen.motion:custom*Valueist ein benutzerdefinierter Wert des im Namen angegebenen Typs. In diesem Beispiel ist der benutzerdefinierte Wert eine angegebene Farbe.
Benutzerdefinierte Werte können einen der folgenden Typen haben:
- Farbe
- Ganzzahl
- Gleitkommazahl
- String
- Dimension
- Boolesch
Mit dieser API kann MotionLayout alles animieren, was einen Setter für eine beliebige Ansicht bietet.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und gehen Sie zu Schritt 6, um die Animation in Aktion zu sehen. Wenn Sie auf den Mond klicken, folgt er dem Pfad vom Start bis zum Ende und durchläuft dabei alle
KeyAttribute, die in derKeyFrameSetangegeben wurden.

Wenn Sie weitere KeyFrames hinzufügen, ändert MotionLayout den Pfad des Mondes von einer geraden Linie zu einer komplexen Kurve. Außerdem werden ein doppelter Rückwärtssalto, eine Größenänderung und ein Farbwechsel in der Mitte der Animation hinzugefügt.
In echten Animationen werden oft mehrere Ansichten gleichzeitig animiert, wobei ihre Bewegung entlang verschiedener Pfade und Geschwindigkeiten gesteuert wird. Wenn Sie für jede Ansicht ein anderes KeyFrame angeben, können Sie komplexe Animationen erstellen, bei denen mehrere Ansichten mit MotionLayout animiert werden.
10. Drag-Ereignisse und komplexe Pfade
In diesem Schritt erfahren Sie, wie Sie OnSwipe mit komplexen Pfaden verwenden. Bisher wurde die Animation des Mondes durch einen OnClick-Listener ausgelöst und lief für eine bestimmte Dauer.
Um Animationen mit komplexen Pfaden wie die Mondanimation, die Sie in den letzten Schritten erstellt haben, mit OnSwipe zu steuern, müssen Sie wissen, wie OnSwipe funktioniert.
Schritt 1: OnSwipe-Verhalten untersuchen
- Öffnen Sie
xml/step7.xmlund suchen Sie nach der vorhandenenOnSwipe-Deklaration.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
/>
- Führen Sie die App auf Ihrem Gerät aus und fahren Sie mit Schritt 7 fort. Versuchen Sie, eine flüssige Animation zu erstellen, indem Sie den Mond entlang des Bogenpfads ziehen.
Wenn Sie diese Animation ausführen, sieht sie nicht sehr gut aus. Nachdem der Mond den höchsten Punkt des Bogens erreicht hat, beginnt er, sich unregelmäßig zu bewegen.

Um den Fehler zu verstehen, sehen Sie sich an, was passiert, wenn der Nutzer den Bogen kurz unter dem oberen Ende berührt. Da das OnSwipe-Tag ein motion:touchAnchorSide="bottom" hat, versucht MotionLayout, den Abstand zwischen dem Finger und dem unteren Rand der Ansicht während der gesamten Animation konstant zu halten.
Da sich der untere Teil des Mondes aber nicht immer in dieselbe Richtung bewegt, sondern erst nach oben und dann wieder nach unten, weiß MotionLayout nicht, was zu tun ist, wenn der Nutzer gerade den höchsten Punkt des Bogens passiert hat. Wenn Sie den unteren Teil des Mondes erfassen, wo sollte er platziert werden, wenn der Nutzer ihn berührt?

Schritt 2: Die richtige Seite verwenden
Um solche Fehler zu vermeiden, ist es wichtig, immer einen touchAnchorId und einen touchAnchorSide auszuwählen, die während der gesamten Animation immer in eine Richtung verlaufen.
In dieser Animation bewegen sich sowohl die right-Seite als auch die left-Seite des Mondes in eine Richtung über den Bildschirm.
Sowohl bottom als auch top kehren jedoch die Richtung um. Wenn OnSwipe versucht, sie zu verfolgen, wird es verwirrt, wenn sich ihre Richtung ändert.
- Damit die Animation auf Berührungsereignisse reagiert, ändern Sie
touchAnchorSideinright.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="right"
/>
Schritt 3: dragDirection verwenden
Sie können dragDirection auch mit touchAnchorSide kombinieren, um einen Seitenpfad in eine andere Richtung zu lenken als normalerweise. Es ist weiterhin wichtig, dass sich die touchAnchorSide nur in eine Richtung bewegt. Sie können MotionLayout jedoch angeben, in welcher Richtung die Bewegung erfasst werden soll. Sie können beispielsweise touchAnchorSide="bottom" beibehalten, aber dragDirection="dragRight" hinzufügen. Dadurch wird die Position des unteren Rands der Ansicht von MotionLayout verfolgt, aber die Position wird nur berücksichtigt, wenn sich der untere Rand nach rechts bewegt (vertikale Bewegungen werden ignoriert). Auch wenn sich der untere Teil auf und ab bewegt, wird er mit OnSwipe korrekt animiert.
- Aktualisiere
OnSwipe, damit die Bewegung des Mondes richtig erfasst wird.
step7.xml
<!-- Using dragDirection to control the direction of drag tracking →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragRight"
/>
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und versuchen Sie, den Mond über den gesamten Pfad zu ziehen. Auch wenn die Animation einen komplexen Bogen beschreibt, kann
MotionLayoutsie als Reaktion auf Wischereignisse fortsetzen.

11. Bewegung mit Code ausführen
Mit MotionLayout lassen sich in Kombination mit CoordinatorLayout ansprechende Animationen erstellen. In diesem Schritt erstellen Sie mit MotionLayout einen minimierbaren Header.
Schritt 1: Vorhandenen Code ansehen
- Öffnen Sie
layout/activity_step8.xml, um zu beginnen. - In
layout/activity_step8.xmlsehen Sie, dass bereits ein funktionierendesCoordinatorLayoutundAppBarLayouterstellt wurde.
activity_step8.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
... >
...
</androidx.constraintlayout.motion.widget.MotionLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
...
motion:layout_behavior="@string/appbar_scrolling_view_behavior" >
...
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
In diesem Layout wird ein CoordinatorLayout verwendet, um Scrollinformationen zwischen dem NestedScrollView und dem AppBarLayout zu teilen. Wenn also NestedScrollView nach oben gescrollt wird, wird AppBarLayout über die Änderung informiert. So implementieren Sie eine zusammenklappbare Symbolleiste wie diese unter Android: Das Scrollen des Texts wird mit dem zusammenklappbaren Header koordiniert.
Die Bewegungsszene, auf die @id/motion_layout verweist, ähnelt der Bewegungsszene im letzten Schritt. Die OnSwipe-Deklaration wurde jedoch entfernt, damit sie mit CoordinatorLayout funktioniert.
- Führen Sie die App aus und fahren Sie mit Schritt 8 fort. Wenn Sie den Text scrollen, sehen Sie, dass sich der Mond nicht bewegt.
Schritt 2: MotionLayout scrollbar machen
- Damit die
MotionLayout-Ansicht scrollt, sobald dieNestedScrollView-Ansicht scrollt, fügen Siemotion:minHeightundmotion:layout_scrollFlagszuMotionLayouthinzu.
activity_step8.xml
<!-- Add minHeight and layout_scrollFlags to the MotionLayout -->
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layoutDescription="@xml/step8"
motion:motionDebug="SHOW_PATH"
android:minHeight="80dp"
motion:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed" >
- Führen Sie die App noch einmal aus und fahren Sie mit Schritt 8 fort. Sie sehen, dass der
MotionLayoutbeim Scrollen nach oben minimiert wird. Die Animation wird jedoch noch nicht auf Grundlage des Scrollverhaltens ausgeführt.
Schritt 3: Bewegung mit Code verschieben
- Öffnen Sie
Step8Activity.kt. Bearbeiten Sie die FunktioncoordinateMotion(), umMotionLayoutüber die Änderungen der Scrollposition zu informieren.
Step8Activity.kt
// TODO: set progress of MotionLayout based on an AppBarLayout.OnOffsetChangedListener
private fun coordinateMotion() {
val appBarLayout: AppBarLayout = findViewById(R.id.appbar_layout)
val motionLayout: MotionLayout = findViewById(R.id.motion_layout)
val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
motionLayout.progress = seekPosition
}
appBarLayout.addOnOffsetChangedListener(listener)
}
Mit diesem Code wird ein OnOffsetChangedListener registriert, das jedes Mal aufgerufen wird, wenn der Nutzer mit dem aktuellen Scroll-Offset scrollt.
MotionLayout unterstützt das Suchen nach dem Übergang durch Festlegen der Eigenschaft „progress“. Wenn Sie zwischen einem verticalOffset und einem prozentualen Fortschritt umrechnen möchten, teilen Sie durch den gesamten Scrollbereich.
Jetzt ausprobieren
- Stellen Sie die App noch einmal bereit und führen Sie die Animation aus Schritt 8 aus. Sie sehen, dass
MotionLayoutdie Animation basierend auf der Scrollposition fortsetzt.

Mit MotionLayout lassen sich benutzerdefinierte dynamische Animationen für minimierbare Symbolleisten erstellen. Mit einer Folge von KeyFrames können Sie sehr auffällige Effekte erzielen.
12. Glückwunsch
In diesem Codelab wurde die grundlegende API von MotionLayout behandelt.
Weitere Beispiele für MotionLayout finden Sie im offiziellen Beispiel. Dokumentation
Weitere Informationen
MotionLayout unterstützt noch mehr Funktionen, die in diesem Codelab nicht behandelt werden, z. B. KeyCycle,, mit dem Sie Pfade oder Attribute mit sich wiederholenden Zyklen steuern können, und KeyTimeCycle,, mit dem Sie Animationen basierend auf der Uhrzeit erstellen können. In den Beispielen finden Sie Beispiele für die einzelnen Typen.
Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage für die Codelabs zum Thema „Erweitertes Android in Kotlin“.