1. Hinweis
Dieses Codelab ist Teil des Kurses „Android in Kotlin für Fortgeschrittene“. Sie profitieren am besten von diesem Kurs, wenn Sie die Codelabs der Reihe nach durcharbeiten. Er ist jedoch nicht obligatorisch. Alle Codelabs des Kurses sind auf der Codelabs-Landingpage für Android in Kotlin aufgeführt.
MotionLayout
ist eine Bibliothek, mit der du deiner Android-App Rich Motion hinzufügen kannst. Es basiert auf ConstraintLayout,
und ermöglicht die Animierung aller Inhalte, die Sie mit ConstraintLayout
erstellen können.
Sie können MotionLayout
verwenden, um Standort, Größe, Sichtbarkeit, Alpha, Farbe, Höhe, Drehung und andere Attribute mehrerer Ansichten gleichzeitig zu animieren. Mit deklarativem XML können Sie koordinierte Animationen mit mehreren Ansichten erstellen, die mit Code nur schwer umzusetzen sind.
Animationen sind eine gute Möglichkeit, die Nutzerfreundlichkeit von Apps zu verbessern. Mit Animationen können Sie:
- Änderungen anzeigen: Durch die Animation zwischen Status können Nutzer Änderungen auf Ihrer Benutzeroberfläche ganz natürlich verfolgen.
- Aufmerksamkeit erregen: Verwenden Sie Animationen, um die Aufmerksamkeit auf wichtige UI-Elemente zu lenken.
- Erstellen Sie wunderschöne Designs: Durch effektive Bewegung im Design sehen Apps optisch ansprechend aus.
Vorbereitung
Dieses Codelab wurde für Entwickler mit ein wenig Erfahrung in der Android-Entwicklung entwickelt. Bevor Sie versuchen, dieses Codelab abzuschließen, sollten Sie Folgendes tun:
- Sie lernen, wie Sie eine App mit einer Aktivität und einem grundlegenden Layout erstellen und sie mit Android Studio auf einem Gerät oder in einem Emulator ausführen. Machen Sie sich mit
ConstraintLayout
vertraut. Weitere Informationen zuConstraintLayout
finden Sie im Codelab für das Einschränkungslayout.
Aufgabe
- Animation mit
ConstraintSets
undMotionLayout
definieren - Basierend auf Drag-Events animieren
- Animation mit
KeyPosition
ändern - Attribute mit
KeyAttribute
ändern - Animationen mit Code ausführen
- Minimierbare Header mit
MotionLayout
animieren
Voraussetzungen
- Android Studio 4.0 (Der
MotionLayout
-Editor funktioniert nur mit dieser Version von Android Studio.)
2. Erste Schritte
Zum Herunterladen der Beispiel-App haben Sie folgende Möglichkeiten:
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 Klicks von Nutzenden vom oberen Anfang des Bildschirms zum unteren Ende verschiebt.
Um eine Animation aus dem Startcode zu erstellen, benötigen Sie die folgenden Hauptbestandteile:
- Ein
MotionLayout,
, das eine abgeleitete Klasse vonConstraintLayout
ist. Sie geben imMotionLayout
-Tag alle Ansichten an, die animiert werden sollen. - Ein
MotionScene,
, also eine XML-Datei, die eine Animation fürMotionLayout.
beschreibt - Ein
Transition,
, das Teil desMotionScene
ist, das die Animationsdauer, den Trigger und die Verschiebung der Ansichten angibt. - Ein
ConstraintSet
, der die Einschränkungen start und end des Übergangs angibt.
Sehen wir uns diese der Reihe nach an, beginnend mit dem MotionLayout
.
Schritt 1: Vorhandenen Code untersuchen
MotionLayout
ist eine abgeleitete Klasse von ConstraintLayout
und unterstützt daher beim Hinzufügen von Animationen dieselben Funktionen. Um MotionLayout
zu verwenden, fügen Sie eine MotionLayout
-Ansicht hinzu, in der Sie ConstraintLayout.
verwenden würden
- Öffnen Sie
activity_step1.xml.
inres/layout
. Hier sehen Sie eineConstraintLayout
mit einem einzelnenImageView
eines Sterns in einer Färbung.
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 ConstraintLayout
gibt es keine Einschränkungen. Wenn Sie die App jetzt ausführen, wäre die Markierung nicht fixiert, d. h., sie würden sich an einer unbekannten Position befinden. Android Studio warnt Sie, wenn keine Einschränkungen vorhanden sind.
Schritt 2: In Motion-Layout konvertieren
Wenn du mit MotionLayout,
animieren möchtest, musst du das ConstraintLayout
in ein MotionLayout
konvertieren.
Damit Ihr Layout eine Bewegungsszene verwenden kann, muss es darauf zeigen.
- Öffnen Sie dazu die Designoberfläche. In Android Studio 4.0 öffnen Sie die Designoberfläche, indem Sie oben rechts in einer Layout-XML-Datei auf das Symbol zum Teilen oder Design klicken.
- Klicken Sie in der Designoberfläche mit der rechten Maustaste auf die Vorschau und wählen Sie Convert to MotionLayout aus.
Dadurch wird das ConstraintLayout
-Tag durch ein MotionLayout
-Tag ersetzt und dem MotionLayout
-Tag 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 Bewegungsszene ist eine einzelne XML-Datei, die eine Animation in einer MotionLayout
beschreibt.
Sobald Sie die Datei in ein MotionLayout
konvertieren, wird auf der Designoberfläche der Bewegungseditor angezeigt.
Der Bewegungseditor enthält drei neue UI-Elemente:
- Übersicht: Dies ist eine modale Auswahl, in der Sie verschiedene Teile der Animation auswählen können. In diesem Bild ist
start
ConstraintSet
ausgewählt. Du kannst auch den Übergang zwischenstart
undend
auswählen, indem du auf den Pfeil dazwischen klickst. - Abschnitt: Unter der Übersicht befindet sich ein Abschnittsfenster, das sich je nach aktuell ausgewähltem Übersichtselement ändert. In diesem Bild werden die Informationen zu
start
ConstraintSet
im Auswahlfenster angezeigt. - Attribut: Im Attributbereich können Sie die Attribute des aktuell ausgewählten Elements im Übersichts- oder Auswahlfenster bearbeiten. Auf diesem Bild sind die Attribute für das
start
-ConstraintSet
zu sehen.
Schritt 3: Start- und Endbeschränkungen definieren
Alle Animationen können als Start und Ende definiert werden. Der Anfang beschreibt, wie der Bildschirm vor der Animation aussieht, und der Ende beschreibt, wie der Bildschirm nach Abschluss der Animation aussieht. MotionLayout
ermittelt, wie die Animation zwischen Start- und Endzustand (im Laufe der Zeit) ablaufen soll.
MotionScene
verwendet ein ConstraintSet
-Tag, um die Start- und Endzustände zu definieren. Ein ConstraintSet
ist, wie es sich anhört, eine Reihe von Einschränkungen, die auf Ansichten angewendet werden können. Dazu gehören Breite, Höhe und ConstraintLayout
-Einschränkungen. Außerdem sind einige Attribute wie alpha
enthalten. Sie enthält nicht die Ansichten selbst, sondern nur die Einschränkungen für diese Ansichten.
Alle in einer ConstraintSet
angegebenen Einschränkungen überschreiben die in der Layoutdatei angegebenen Einschränkungen. Wenn Sie Einschränkungen sowohl im Layout als auch im MotionScene
definieren, werden nur die Einschränkungen in der MotionScene
angewendet.
In diesem Schritt legen Sie fest, dass die Sternansicht am oberen Anfang des Bildschirms beginnt und am unteren Ende des Bildschirms endet.
Du kannst dazu entweder den Bewegungseditor verwenden oder den Text von activity_step1_scene.xml
direkt bearbeiten.
- Im Übersichtsbereich das ConstraintSet
start
auswählen
- Wählen Sie im Auswahlbereich die Option
red_star
aus. Aktuell wird die Quellelayout
angezeigt. Das bedeutet, dass sie in dieserConstraintSet
nicht eingeschränkt ist. Verwenden Sie das Stiftsymbol oben rechts, um Einschränkung erstellen zu erstellen.
- Prüfen Sie, ob
red_star
als Quellestart
angezeigt wird, wennstart
ConstraintSet
im Übersichtsbereich ausgewählt ist. - Fügen Sie im Bereich „Attribute“ mit der Option
red_star
in derstart
ConstraintSet
oben eine Einschränkung hinzu und klicken Sie zuerst auf die blauen +-Schaltflächen.
- Öffnen Sie
xml/activity_step1_scene.xml
, um den Code anzusehen, den der Bewegungseditor 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>
ConstraintSet
hat als id
den Wert @id/start
und gibt alle Einschränkungen an, die für alle Ansichten in MotionLayout
gelten. Da dieses MotionLayout
nur eine Ansicht hat, ist nur eine Constraint
erforderlich.
Die Constraint
innerhalb der ConstraintSet
gibt die ID der Ansicht an, die eingeschränkt wird, @id/red_star
, die in activity_step1.xml
definiert ist. Beachten Sie, dass Constraint
-Tags nur Einschränkungen und Layoutinformationen angeben. Das Constraint
-Tag weiß nicht, dass es auf ImageView
angewendet wird.
Diese Einschränkung gibt die Höhe, Breite und die beiden anderen Einschränkungen an, die erforderlich sind, um die Ansicht red_star
auf den oberen Anfang des übergeordneten Elements zu beschränken.
- Wählen Sie im Übersichtsbereich die ConstraintSet
end
aus.
- Führen Sie dieselben Schritte wie zuvor aus, um ein
Constraint
fürred_star
in derend
ConstraintSet
hinzuzufügen. - Um diesen Schritt mit dem Bewegungseditor abzuschließen, fügen Sie
bottom
undend
eine Einschränkung hinzu, indem Sie auf die blauen +-Schaltflächen klicken.
- Der Code in XML sieht wie folgt 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>
Genau wie @id/start
hat dieses ConstraintSet
ein einzelnes Constraint
auf @id/red_star
. Diesmal ist er auf das untere Ende des Bildschirms beschränkt.
Sie müssen sie nicht @id/start
und @id/end
nennen, das ist aber praktisch.
Schritt 4: Übergang festlegen
Jede MotionScene
muss außerdem mindestens einen Übergang enthalten. Ein Übergang definiert jeden Teil einer Animation, vom Anfang bis zum Ende.
Für einen Übergang müssen Start- und End-ConstraintSet
für den Übergang angegeben werden. Mit einem Übergang können Sie auch festlegen, wie die Animation auf andere Weise geändert werden soll, z. B. wie lange die Animation abgespielt werden soll oder wie durch Ziehen von Ansichten animiert werden soll.
- Der Bewegungs-Editor hat beim Erstellen der MotionScene-Datei standardmäßig einen Übergang 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 genauer an:
constraintSetStart
wird auf die Ansichten angewendet, wenn die Animation beginnt.constraintSetEnd
wird auf die Ansichten am Ende der Animation angewendet.duration
gibt an, wie lange die Animation dauern soll (in Millisekunden).
MotionLayout
ermittelt dann einen Pfad zwischen den Start- und Endeinschränkungen und animiert ihn für die angegebene Dauer.
Schritt 5: Vorschau der Animation im Motion Editor ansehen
Animation:Video der Wiedergabe einer Übergangsvorschau im Motion Editor
- Öffnen Sie den Bewegungs-Editor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen
start
undend
klicken.
- Wenn ein Übergang ausgewählt ist, werden im Auswahlbereich die Steuerelemente für die Wiedergabe und eine Scrubbing-Leiste angezeigt. Klicken Sie auf „Wiedergabe“ oder ziehen Sie die aktuelle Position, um eine Vorschau der Animation anzusehen.
Schritt 6: Bei Klick-Handler hinzufügen
Sie müssen einen Weg finden, um die Animation zu starten. Dazu kannst du beispielsweise dafür sorgen, dass MotionLayout
auf Click-Events auf @id/red_star
reagiert.
- Öffnen Sie den Bewegungs-Editor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen Start und Ende klicken.
- Klicken Sie in der Symbolleiste des Übersichtssteuerfelds auf Klick- oder Wisch-Handler erstellen . Dadurch wird ein Handler hinzugefügt, mit dem ein Übergang gestartet wird.
- Wählen Sie im Pop-up die Option Click Handler (Klick-Handler) aus.
- Ändern Sie View To Click in
red_star
.
- Klicken Sie auf Add (Hinzufügen). Der Klick-Handler wird durch einen kleinen Punkt auf dem Übergang im Motion Editor dargestellt.
- Wählen Sie den Übergang im Übersichtsbereich aus und fügen Sie dem gerade im Attributbereich hinzugefügten OnClick-Handler das
clickAction
-Attributtoggle
hinzu.
- Ö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>
Transition
weist MotionLayout
an, die Animation als Reaktion auf Click-Events mithilfe eines <OnClick>
-Tags auszuführen. Sehen wir uns die einzelnen Attribute genauer an:
targetId
ist die Ansicht, die auf Klicks überwacht werden soll.clickAction
vontoggle
wechselt beim Klicken zwischen Start- und Endstatus. Weitere Optionen fürclickAction
finden Sie in der Dokumentation.
- Führen Sie Ihren Code aus, klicken Sie auf Schritt 1, dann auf den roten Stern und sehen Sie sich die Animation an.
Schritt 5: Animationen in Aktion
Führen Sie die App aus. Wenn Sie auf den Stern klicken, sollte die Animation laufen.
In der fertigen Bewegungsszenendatei wird ein Transition
definiert, der auf einen Start- und ein End-ConstraintSet
verweist.
Zu Beginn der Animation (@id/start
) wird das Sternsymbol am oberen Anfang des Bildschirms fixiert. Am Ende der Animation (@id/end
) wird das Sternsymbol am unteren Bildschirmrand 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. Animation basierend auf Drag-Events
Für diesen Schritt erstellen Sie eine Animation, die auf ein Drag-Event des Nutzers reagiert (wenn der Nutzer über den Bildschirm wischt), um die Animation auszuführen. MotionLayout
unterstützt das Erfassen von Touch-Ereignissen zum Verschieben von Ansichten sowie physikbasierte Fliegebewegungen, um Bewegungen flüssig zu machen.
Schritt 1: Anfangscode prüfen
- Öffnen Sie dazu die Layoutdatei
activity_step2.xml
, in der bereitsMotionLayout
vorhanden ist. Werfen Sie einen Blick auf den Code.
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>
Mit diesem Layout werden alle Ansichten für die Animation definiert. Die drei Sternsymbole sind im Layout nicht fixiert, da sie in der Bewegungsszene animiert werden.
Für die Gutschriften TextView
gelten Einschränkungen, da sie während der gesamten Animation an derselben Stelle bleiben und keine Attribute ändern.
Schritt 2: Szene animieren
Genau wie bei der letzten Animation wird auch die Animation durch ein ConstraintSet,
-Element am Anfang und Ende sowie durch ein Transition
-Element definiert.
Definieren Sie den Start-ConstraintSet-Wert
- Öffnen Sie die Bewegungsszene
xml/step2.xml
, um die Animation zu definieren. - Fügen Sie die Einschränkungen für die Starteinschränkung
start
hinzu. Zu Beginn sind alle drei Sterne unten auf dem Bildschirm zentriert. Der rechte und linke Stern 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 ein Constraint
-Element für jeden der Sterne an. Jede Einschränkung wird von MotionLayout
zu Beginn der Animation angewendet.
Jede Markierung wird unten auf dem Bildschirm mithilfe von Beschränkungen am Anfang, am Ende und am unteren Rand zentriert. Die beiden Sterne @id/left_star
und @id/right_star
haben beide einen zusätzlichen Alphawert, der sie unsichtbar macht und zu Beginn der Animation angewendet wird.
Die Einschränkungssätze start
und end
definieren Start und Ende der Animation. Durch eine Einschränkung am Anfang wie motion:layout_constraintStart_toStartOf
wird der Start einer Ansicht auf den Anfang einer anderen Ansicht beschränkt. Dies kann zunächst verwirrend sein, da der Name start
sowohl für als auch im Kontext von Einschränkungen verwendet wird. Um die Unterscheidung zu verdeutlichen, bezieht sich start
in layout_constraintStart
auf den „Start“. der Ansicht, die links für eine von links nach rechts und rechts für eine linksläufige Sprache ist. Der Einschränkungssatz start
bezieht sich auf den Beginn der Animation.
End ConstraintSet definieren
- Definieren Sie die Endbindung so, dass alle drei Sterne mithilfe einer Kette unter
@id/credits
positioniert werden. Außerdem wird der Endwert vonalpha
der linken und rechten Sterne auf1.0
gesetzt.
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 führt dazu, dass sich die Ansichten während der Animation von der Mitte aus nach oben ausbreiten.
Da die Eigenschaft alpha
in beiden ConstraintSets
auf @id/right_start
und @id/left_star
festgelegt ist, werden beide Ansichten im Laufe der Animation eingeblendet.
Animation basierend auf Wischen des Nutzers
MotionLayout
kann Drag-Events des Nutzers oder Wischen erfassen, um einen physikbasierten „Schlag“ zu erstellen Animation. Das heißt, die Ansichten bleiben erhalten, wenn der Nutzer sie wirft, und verlangsamt sich wie ein physisches Objekt, wenn er sich über eine Oberfläche bewegt. Sie können diese Art von Animation mit einem OnSwipe
-Tag im Transition
hinzufügen.
- Ersetzen Sie den TODO-Eintrag zum 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. Das wichtigste ist touchAnchorId
.
touchAnchorId
ist die erfasste Ansicht, die sich als Reaktion auf eine Berührung bewegt. InMotionLayout
wird in dieser Ansicht derselbe Abstand zu dem Finger beibehalten, mit dem gewischt wird.- Mit
touchAnchorSide
wird festgelegt, welche Seite der Ansicht erfasst werden soll. Dies ist wichtig für Ansichten, deren Größe angepasst wird, die komplexen Pfaden folgen oder deren Seite sich schneller bewegt als die andere. - Mit
dragDirection
wird festgelegt, welche Richtung für die Animation wichtig ist (nach oben, unten, links oder rechts).
Wenn MotionLayout
auf Drag-Ereignisse wartet, wird der Listener in der MotionLayout
-Ansicht und nicht in der durch touchAnchorId
angegebenen Ansicht registriert. Wenn ein Nutzer irgendwo auf dem Bildschirm eine Geste startet, hält MotionLayout
den Abstand zwischen seinem Finger und der touchAnchorSide
-Ansicht in der touchAnchorId
-Ansicht konstant. Wenn der Nutzer beispielsweise 100 dp von der Ankerseite entfernt berührt, hält MotionLayout
diese Seite während der gesamten Animation 100 dp vom Finger entfernt.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und öffnen Sie Schritt 2. Sie sehen die Animation.
- Sag zum Beispiel „schleppen“ oder lassen Sie den Finger nach der Hälfte der Animation los, um zu erfahren, wie
MotionLayout
Animationen basierend auf flüssiger Physik anzeigt.
MotionLayout
kann mit den Funktionen von ConstraintLayout
zwischen sehr verschiedenen Designs animiert werden, um ansprechende Effekte zu erzeugen.
In dieser Animation werden alle drei Ansichten am unteren Bildschirmrand relativ zum übergeordneten Element positioniert. Am Ende werden die drei Ansichten relativ zu @id/credits
in einer Kette positioniert.
Trotz dieser sehr unterschiedlichen Layouts erzeugt MotionLayout
eine fließende Animation zwischen Start und Ende.
5. Pfad ändern
In diesem Schritt erstellen Sie eine Animation, die während der Animation einem komplexen Pfad folgt und die Credits während der Bewegung animiert. Mit MotionLayout
kann der Pfad einer Ansicht zwischen dem Start und dem Ende mithilfe von KeyPosition
geändert werden.
Schritt 1: Vorhandenen Code untersuchen
- Öffnen Sie
layout/activity_step3.xml
undxml/step3.xml
, um das vorhandene Layout und die vorhandene Bewegungsszene zu sehen.ImageView
undTextView
zeigen den Mond und die Quellenangaben an. - Öffnen Sie die Datei mit der Bewegungsszene (
xml/step3.xml
). Sie sehen, dass eineTransition
von@id/start
bis@id/end
definiert ist. Bei der Animation wird das Mondbild mithilfe von zweiConstraintSets
von links unten nach rechts unten auf dem Bildschirm verschoben. Während der Mond bewegt wird, wird der Beitragstext vonalpha="0.0"
bisalpha="1.0"
eingeblendet. - Führen Sie die App jetzt aus und wählen Sie Schritt 3 aus. Wenn Sie auf den Mond klicken, folgt er von Anfang bis Ende einem linearen Pfad (oder einer geraden Linie).
Schritt 2: Fehlerbehebung bei Pfaden aktivieren
Bevor du der Bewegung des Mondes einen Bogen hinzufügst, ist es hilfreich, die Fehlerbehebung für Pfaden in MotionLayout
zu aktivieren.
Um komplexe Animationen mit MotionLayout
zu entwickeln, können Sie den Animationspfad jeder Ansicht zeichnen. Dies ist hilfreich, wenn Sie Ihre Animation visualisieren und die kleinen Bewegungsdetails feinabstimmen möchten.
- Wenn Sie Debugging-Pfade aktivieren möchten, öffnen Sie
layout/activity_step3.xml
und 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" >
Nachdem Sie das Pfad-Debugging aktiviert haben und die Anwendung erneut ausführen, werden die Pfade aller Ansichten mit einer gepunkteten Linie dargestellt.
- Kreise stellen die Start- oder Endposition einer Ansicht dar.
- Linien stellen den Pfad einer Ansicht dar.
- Rauten stehen für eine
KeyPosition
, die den Pfad ändert.
In dieser Animation ist der mittlere Kreis beispielsweise die Position des Texts für die Mitwirkenden.
Schritt 3: Pfad ändern
Alle Animationen in MotionLayout
werden durch einen Start- und einen End-ConstraintSet
definiert, der festlegt, wie der Bildschirm vor und nach dem Start der Animation aussieht. Standardmäßig stellt MotionLayout
einen linearen Pfad (eine gerade Linie) zwischen der Start- und Endposition jeder Ansicht dar, die sich die Position ändert.
Um komplexe Pfade wie in diesem Beispiel den Bogen des Mondes zu erstellen, verwendet MotionLayout
ein KeyPosition
, um den Pfad zu ändern, den eine Ansicht zwischen Start und Ende zurücklegt.
- Öffne
xml/step3.xml
und füge der Szene einKeyPosition
hinzu. 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 einem Transition
untergeordnet und besteht aus allen KeyFrames
, z. B. KeyPosition
, die während des Übergangs angewendet werden sollen.
Wenn MotionLayout
den Weg für den Mond zwischen Start und Ende berechnet, wird der Pfad entsprechend dem in KeyFrameSet
angegebenen KeyPosition
geändert. Sie können sehen, wie dadurch der Pfad geändert wird, indem Sie die Anwendung noch einmal ausführen.
Ein KeyPosition
hat mehrere Attribute, die beschreiben, wie der Pfad geändert wird. Die wichtigsten sind:
framePosition
ist eine Zahl zwischen 0 und 100. Damit wird definiert, wann in der Animation diesesKeyPosition
angewendet werden soll, wobei 1 für 1% durch die Animation und 99 für 99% durch die Animation steht. Wenn der Wert also 50 ist, wird er direkt in der Mitte angewendet.motionTarget
ist die Ansicht, für die dieserKeyPosition
den Pfad ändert.- Mit
keyPositionType
ändertKeyPosition
den Pfad. Es kann entwederparentRelative
,pathRelative
oderdeltaRelative
sein (wie im nächsten Schritt erläutert). percentX | percentY
gibt an, wie stark der Pfad beiframePosition
geändert werden soll (Werte zwischen 0,0 und 1,0, wobei negative Werte und Werte > 1 zulässig sind).
Sie können es sich so vorstellen: "Bei framePosition
ändern Sie den Pfad von motionTarget
indem Sie ihn um percentX
oder percentY
entsprechend den durch keyPositionType
festgelegten Koordinaten verschieben."
Standardmäßig rundet MotionLayout
alle Ecken ab, die durch eine Änderung des Pfads entstehen. In der Animation, die Sie gerade erstellt haben, sehen Sie, dass der Mond an der Krümmung einer Kurve folgt. Für die meisten Animationen ist dies das Gewünschte. Falls nicht, können Sie das Attribut curveFit
angeben, um es anzupassen.
Jetzt ausprobieren
Wenn Sie die App wieder ausführen, sehen Sie die Animation für diesen Schritt.
Der Mond folgt einem Bogen, weil er durch eine KeyPosition
verläuft, die in der Transition
angegeben ist.
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
Sie können diese KeyPosition
so lesen: „Verändere bei framePosition 50
(in der Hälfte der Animation) den Pfad von motionTarget
@id/moon
, indem du ihn gemäß den durch parentRelative
(gesamten MotionLayout
) festgelegten Koordinaten um 50% Y
(die Hälfte des Bildschirms nach unten) verschiebst.“
Nach der Hälfte der Animation muss der Mond durch einen KeyPosition
verlaufen, der sich 50% unter dem Bildschirm befindet. Diese KeyPosition
ändert die X-Bewegung überhaupt nicht, der Mond bewegt sich also trotzdem horizontal von Anfang bis Ende. MotionLayout
ermittelt einen gleichmäßigen Pfad, der durch diese KeyPosition
verläuft, während sie zwischen Anfang und Ende verläuft.
Wenn Sie genau hinsehen, ist der Text für die Quellenangaben durch die Position des Mondes beschränkt. Warum bewegt sie sich nicht auch vertikal?
<Constraint
android:id="@id/credits"
...
motion:layout_constraintBottom_toBottomOf="@id/moon"
motion:layout_constraintTop_toTopOf="@id/moon"
/>
Wie sich herausstellt, verschieben Sie den Weg des Mondes zwar nicht, aber die Start- und Endpositionen verschieben ihn nicht vertikal. Die KeyPosition
ändert weder die Start- noch die Endposition, sodass der Beitragstext auf die endgültige Endposition des Mondes beschränkt ist.
Wenn du möchtest, dass sich die Credits zusammen mit dem Mond bewegen, kannst du KeyPosition
zu den Credits hinzufügen oder die Startbeschränkungen für @id/credits
ändern.
Im nächsten Abschnitt sehen wir uns die verschiedenen Arten von keyPositionType
in MotionLayout
genauer an.
6. Informationen zu keyPositionType
Im letzten Schritt haben Sie parentRelative
vom Typ keyPosition
verwendet, um den Pfad um 50% des Bildschirms zu verschieben. Das Attribut keyPositionType
bestimmt, wie MotionLayout den Pfad entsprechend 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
. Die Angabe eines Typs ändert das Koordinatensystem, nach dem percentX
und percentY
berechnet werden.
Was ist ein Koordinatensystem?
Mithilfe eines Koordinatensystems kann ein Punkt im Raum angegeben werden. Sie sind auch nützlich, um eine Position auf dem Bildschirm zu beschreiben.
MotionLayout
-Koordinatensysteme sind ein kartesisches Koordinatensystem. Das heißt, sie haben eine X- und eine Y-Achse, die durch zwei senkrechte Linien definiert sind. Der Hauptunterschied besteht darin, wo auf dem Bildschirm die X-Achse verläuft (die Y-Achse steht 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. Der percentX
-Wert -2.0
würde also beispielsweise zweimal in die entgegengesetzte Richtung der X-Achse gehen.
Wenn das alles ein bisschen zu sehr nach Algebra-Kurs klingt, schauen Sie sich die Bilder unten an.
parentRelative Koordinaten
Für keyPositionType
von parentRelative
wird dasselbe Koordinatensystem wie für den Bildschirm verwendet. Er definiert (0, 0)
oben links vom gesamten MotionLayout
und (1, 1)
unten rechts.
Du kannst parentRelative
jederzeit verwenden, wenn du eine Animation erstellen möchtest, die sich durch die gesamte MotionLayout
bewegt – wie in diesem Beispiel der Mondbogen.
Wenn Sie jedoch einen Pfad relativ zur Bewegung ändern möchten, z. B. um ihn nur ein wenig zu krümmen, sind die anderen beiden Koordinatensysteme besser geeignet.
deltaRelative-Koordinaten
Delta ist ein mathematischer Ausdruck für Änderung, also steht deltaRelative
für „Änderung relativ“. In den deltaRelative
-Koordinaten ist (0,0)
die Startposition der Ansicht und (1,1)
die Endposition. Die X- und Y-Achse sind am Bildschirm ausgerichtet.
Die X-Achse ist auf dem Bildschirm immer horizontal und die Y-Achse immer vertikal auf dem Bildschirm. 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 horizontale oder vertikale Bewegungen isoliert zu steuern. Sie könnten beispielsweise eine Animation erstellen, die nur die vertikale (Y) Bewegung bei 50 % abgeschlossen und die Animation horizontal fortgesetzt wird (X).
pathRelative-Koordinaten
Das letzte Koordinatensystem in MotionLayout
ist pathRelative
. Sie unterscheidet sich stark von den anderen beiden, da die X-Achse dem Bewegungspfad von Anfang bis Ende folgt. (0,0)
ist also die Startposition und (1,0)
die Endposition.
Wozu dient das? Das ist auf den ersten Blick ziemlich überraschend, vor allem, da dieses Koordinatensystem nicht einmal am Bildschirmkoordinatensystem ausgerichtet ist.
pathRelative
ist für einige Dinge sehr nützlich.
- Beschleunigen, Verlangsamen oder Anhalten eines Aufrufs während eines Teils der Animation Da die Dimension X immer genau mit dem Pfad übereinstimmt, den die Ansicht nimmt, können Sie mit
pathRelative
KeyPosition
ändern, welcheframePosition
ein bestimmter Punkt im Pfad erreicht wird. EinKeyPosition
beiframePosition="50"
mit einempercentX="0.1"
würde also dazu führen, dass die Animation die ersten 10% der Bewegung in 50% der Zeit zurücklegt. - Einen dezenten Bogen zu einem Pfad hinzufügen Da die Y-Dimension immer senkrecht zur Bewegung steht, ändert sich durch eine Änderung von Y der Pfad in die Kurve relativ zur gesamten Bewegung.
- Eine zweite Dimension für den Fall hinzufügen, dass
deltaRelative
nicht funktioniert Bei vollständig horizontalen und vertikalen Bewegungen erzeugtdeltaRelative
nur eine nützliche Dimension.pathRelative
erstellt jedoch immer verwendbare X- und Y-Koordinaten.
Im nächsten Schritt erfahren Sie, wie Sie mit mehr als einem KeyPosition
noch komplexere Pfade erstellen.
7. Komplexe Pfade erstellen
Die Animation, die Sie im letzten Schritt erstellt haben, sieht zwar eine sanfte Kurve, aber die Form könnte eher "Mondartig" sein.
Pfad mit mehreren KeyPosition-Elementen ändern
MotionLayout
kann einen Pfad weiter ändern, indem so viele KeyPosition
definiert werden, wie für eine Bewegung erforderlich sind. Für diese Animation erstellen Sie einen Bogen, aber Sie könnten den Mond in der Bildschirmmitte dazu bringen, auf und ab zu springen, wenn Sie möchten.
- Öffnen Sie
xml/step4.xml
. Sie enthält dieselben Aufrufe und dieKeyFrame
, die Sie im letzten Schritt hinzugefügt haben. - Um den oberen Rand der Kurve zu runden, addieren Sie zwei weitere
KeyPositions
zum Pfad von@id/moon
: eine kurz vor dem oberen Rand und eine danach.
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 25% und 75% der gesamten Animation angewendet und bewirken, dass @id/moon
sich durch einen Pfad bewegt, der 60% vom oberen Bildschirmrand entfernt ist. In Kombination mit der vorhandenen KeyPosition
von 50 % entsteht dadurch ein gleichmäßiger Bogen, dem der Mond folgen kann.
In MotionLayout
können Sie so viele KeyPositions
hinzufügen, wie nötig sind, um den gewünschten Bewegungspfad zu erhalten. MotionLayout
wendet jedes KeyPosition
-Element beim angegebenen framePosition
-Wert an und ermittelt, wie eine sanfte Bewegung erstellt wird, die alle KeyPositions
durchläuft.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus. Fahren Sie mit Schritt 4 fort, um die Animation in Aktion zu sehen. Wenn Sie auf den Mond klicken, folgt er dem Pfad von Anfang bis Ende, indem er jeden
KeyPosition
durchläuft, der in derKeyFrameSet
angegeben wurde.
Auf eigene Faust erkunden
Bevor du zu anderen KeyFrame
-Typen übergehst, versuche, dem KeyFrameSet
etwas mehr KeyPositions
hinzuzufügen, um zu sehen, welche Effekte du nur mit KeyPosition
erstellen kannst.
Das folgende Beispiel zeigt, wie Sie einen komplexen Pfad erstellen, der sich während der Animation vor- und zurückbewegt.
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 sich mit KeyPosition
vertraut gemacht haben, können Sie im nächsten Schritt mit anderen KeyFrames
-Typen fortfahren.
8. Ändern von Attributen während der Bewegung
Das Erstellen dynamischer Animationen bedeutet häufig, dass size
, rotation
oder alpha
der Ansichten im Laufe der Animation geändert werden. MotionLayout
unterstützt die Animation vieler Attribute in einer beliebigen Ansicht mithilfe von KeyAttribute
.
In diesem Schritt verwenden Sie KeyAttribute
, um den Mond zu skalieren und zu drehen. Außerdem wird KeyAttribute
verwendet, um das Erscheinen des Textes zu verzögern, bis der Mond seine Reise fast abgeschlossen hat.
Schritt 1: Größe und Rotation mit KeyAttribute anpassen
- Öffnen Sie
xml/step5.xml
. Es enthält dieselbe Animation, die Sie im letzten Schritt erstellt haben. Zur Abwechslung wird auf diesem Bildschirm ein anderes Weltraumbild als Hintergrund verwendet. - Damit der Mond größer angezeigt und gedreht werden kann, fügen Sie zwei
KeyAttribute
-Tags in dieKeyFrameSet
beikeyFrame="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% befindet sich oben im Bogen und führt dazu, dass sich die Ansicht verdoppelt und sie um -360 Grad gedreht wird. Mit dem zweiten KeyAttribute
wird die zweite Drehung auf -720 Grad (zwei vollständige Kreise) abgeschlossen und die Größe wieder auf den regulären Wert zurückgesetzt, da die Werte scaleX
und scaleY
standardmäßig auf 1,0 gesetzt sind.
Genau wie ein KeyPosition
verwendet ein KeyAttribute
die framePosition
und motionTarget
, um anzugeben, wann KeyFrame
angewendet und welche Ansicht geändert werden soll. MotionLayout
interpoliert zwischen KeyPositions
und erstellt flüssige Animationen.
KeyAttributes
unterstützt Attribute, die auf alle Ansichten angewendet werden können. Damit lassen sich grundlegende Attribute wie visibility
, alpha
oder elevation
ändern. Sie können die Drehung auch wie hier beschrieben ändern, mit rotateX
und rotateY
in drei Dimensionen drehen, die Größe mit scaleX
und scaleY
skalieren oder die Position der Ansicht in X, Y oder Z verschieben.
Schritt 2: Anzeige von Mitwirkenden verzögern
In diesem Schritt soll unter anderem die Animation aktualisiert werden, sodass der Text für die Mitwirkenden erst angezeigt wird, wenn die Animation vollständig abgeschlossen ist.
- Wenn Sie die Anzeige von Gutschriften verzögern möchten, definieren Sie eine weitere
KeyAttribute
, die dafür sorgt, dassalpha
bis zumkeyPosition="85"
„0“ bleibt.MotionLayout
wechselt trotzdem nahtlos von 0 zu 100 Alpha, aber dies geschieht über die 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"
/>
Mit diesem KeyAttribute
bleibt der alpha
von @id/credits
für die ersten 85% der Animation bei 0,0. Da die Animation bei einem Alphawert von 0 beginnt, ist sie für die ersten 85% der Animation unsichtbar.
Bei diesem KeyAttribute
erscheinen die Mitwirkenden gegen Ende der Animation. Dadurch sieht es so aus, als wären sie koordiniert mit dem Mond in der rechten Ecke des Bildschirms.
Wenn Sie Animationen bei einer Ansicht verzögern, während eine andere so bewegt wird, 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 fahren Sie mit Schritt 5 fort, um die Animation in Aktion zu sehen. Wenn Sie auf den Mond klicken, folgt er dem Pfad von Anfang bis Ende, indem er jeden
KeyAttribute
durchläuft, der in derKeyFrameSet
angegeben wurde.
Da du den Mond um zwei volle Kreise drehst, wird jetzt ein doppelter Umblättern-Effekt ausgeführt. Die Credits erscheinen, bis die Animation fast fertig ist.
Eigenständig erkunden
Bevor Sie mit dem letzten Typ von KeyFrame
fortfahren, versuchen Sie, andere Standardattribute in KeyAttributes
zu ändern. Ändern Sie beispielsweise rotation
in rotationX
, um zu sehen, welche Animation erzeugt wird.
Nachfolgend finden Sie eine Liste der Standardattribute, die Sie ausprobieren können:
android:visibility
android:alpha
android:elevation
android:rotation
android:rotationX
android:rotationY
android:scaleX
android:scaleY
android:translationX
android:translationY
android:translationZ
9. Benutzerdefinierte Attribute ändern
Bei komplexen Animationen werden die Farbe oder andere Attribute einer Ansicht geändert. Während MotionLayout
mit einem KeyAttribute
alle in der vorherigen Aufgabe aufgeführten Standardattribute ändern kann, können Sie mit einem CustomAttribute
alle anderen Attribute angeben.
Mit CustomAttribute
kann jeder Wert mit einem Setter festgelegt werden. Sie können beispielsweise die backgroundColor in einer Ansicht mithilfe eines CustomAttribute
festlegen. MotionLayout
nutzt die Reflexion, 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
auf dem Mond festzulegen und die unten gezeigte Animation zu erstellen.
Benutzerdefinierte Attribute definieren
- Öffnen Sie zunächst
xml/step6.xml
. Es enthält dieselbe Animation, die Sie im letzten Schritt erstellt haben. - Damit sich die Farbe des Mondes ändert, musst du zwei
KeyAttribute
mit einemCustomAttribute
in dieKeyFrameSet
beikeyFrame="0"
,keyFrame="50"
undkeyFrame="100".
addieren
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 einem KeyAttribute
hinzu. CustomAttribute
wird an der durch KeyAttribute
angegebenen framePosition
angewendet.
Innerhalb des CustomAttribute
müssen Sie eine attributeName
und einen Wert angeben, der festgelegt werden soll.
motion:attributeName
ist der Name des Setters, der von diesem benutzerdefinierten Attribut aufgerufen wird. In diesem Beispiel wirdsetColorFilter
amDrawable
aufgerufen.motion:custom*Value
ist ein benutzerdefinierter Wert des im Namen angegebenen Typs. In diesem Beispiel ist der benutzerdefinierte Wert eine angegebene Farbe.
Benutzerdefinierte Werte können folgende Typen haben:
- Farbe
- Ganzzahl
- Gleitkommazahl
- String
- Dimension
- Boolesch
Mit dieser API kann MotionLayout
alles animieren, was einen Setter für jede Ansicht bietet.
Jetzt ausprobieren
- Führen Sie die App noch einmal aus und fahren Sie mit Schritt 6 fort, um die Animation in Aktion zu sehen. Wenn Sie auf den Mond klicken, folgt er dem Pfad von Anfang bis Ende, indem er jeden
KeyAttribute
durchläuft, der in derKeyFrameSet
angegeben wurde.
Wenn du weitere KeyFrames
hinzufügst, ändert MotionLayout
den Pfad des Mondes von einer geraden Linie in eine komplexe Kurve. Dabei werden mitten in der Animation ein doppelter Rückwärtssalto, eine Größenänderung und eine Farbänderung hinzugefügt.
In echten Animationen animieren Sie häufig mehrere Ansichten gleichzeitig und steuern deren Bewegung entlang unterschiedlicher Pfade und Geschwindigkeiten. Wenn Sie für jede Ansicht ein anderes KeyFrame
-Objekt angeben, ist es möglich, komplexe Animationen, die mehrere Ansichten animieren, mit MotionLayout
zu choreografieren.
10. Drag-Events und komplexe Pfade
In diesem Schritt erfahren Sie, wie Sie OnSwipe
mit komplexen Pfaden verwenden. Bisher wurde die Mondanimation durch einen OnClick
-Listener ausgelöst und läuft für eine festgelegte Dauer.
Wenn Sie mit OnSwipe
Animationen mit komplexen Pfaden steuern möchten, wie die Mondanimation, die Sie in den letzten Schritten erstellt haben, müssen Sie sich mit der Funktionsweise von OnSwipe
vertraut machen.
Schritt 1: Verhalten beim Wischen über das Display erkunden
- Öffnen Sie
xml/step7.xml
und suchen Sie die vorhandeneOnSwipe
-Deklaration.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
/>
- Führen Sie die App auf dem Gerät aus und fahren Sie mit Schritt 7 fort. Versuchen Sie, eine flüssige Animation zu erstellen, indem Sie den Mond entlang des Bogens ziehen.
Wenn Sie diese Animation ausführen, sieht sie nicht sehr gut aus. Nachdem der Mond die Spitze des Bogens erreicht hat, fängt er an zu hüpfen.
Um den Programmfehler zu verstehen, überlegen Sie, was passiert, wenn der Benutzer direkt unter den oberen Bereich des Bogens rührt. Da das OnSwipe
-Tag ein motion:touchAnchorSide="bottom"
enthält, 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 Rand des Mondes jedoch nicht immer in dieselbe Richtung bewegt, geht er nach oben und dann wieder nach unten. MotionLayout
weiß also nicht, was zu tun ist, wenn der Nutzer gerade den Bogen gerade passiert. Da Sie den Boden des Mondes verfolgen, wo sollte er platziert werden, wenn der Nutzer hierhin tippt?
Schritt 2: Die rechte Seite verwenden
Um Fehler wie diese zu vermeiden, ist es wichtig, immer eine touchAnchorId
und touchAnchorSide
auszuwählen, die während der gesamten Animation immer in eine Richtung voranschreitet.
In dieser Animation verlaufen sowohl die right
-Seite als auch die left
-Seite des Mondes in einer Richtung über den Bildschirm.
Die Richtung wird jedoch sowohl mit bottom
als auch mit top
umgekehrt. Wenn OnSwipe
versucht, sie zu verfolgen, ist es verwirrend, wenn sich die Richtung ändert.
- Wenn diese Animation Touch-Events folgen soll, ändere die
touchAnchorSide
zuright
.
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 eine seitliche Fahrtrichtung anders zu gestalten als sonst. Es ist weiterhin wichtig, dass der touchAnchorSide
nur in eine Richtung voranschreitet. Sie können MotionLayout
jedoch angeben, in welche Richtung Sie erfassen möchten. Sie können beispielsweise die touchAnchorSide="bottom"
beibehalten, aber dragDirection="dragRight"
hinzufügen. Dies führt dazu, dass MotionLayout
die Position des unteren Rands der Ansicht erfasst, aber nur bei einer Bewegung nach rechts seine Position berücksichtigt. Die vertikale Bewegung wird ignoriert. Auch wenn der untere Bereich nach oben und unten verläuft, wird die Animation mit OnSwipe
dennoch korrekt fortgesetzt.
- Aktualisiere
OnSwipe
, um die Bewegung des Mondes korrekt zu erfassen.
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 in
MotionLayout
verlaufen ist, kann sie als Reaktion auf Wisch-Ereignisse fortgesetzt werden.
11. Laufende Bewegung mit Code
MotionLayout
kann zusammen mit CoordinatorLayout
verwendet werden, um komplexe Animationen zu erstellen. In diesem Schritt erstellen Sie mit MotionLayout
einen minimierbaren Header.
Schritt 1: Vorhandenen Code untersuchen
- Öffne
layout/activity_step8.xml
, um loszulegen. - Sie sehen in
layout/activity_step8.xml
, dass bereits eine funktionierendeCoordinatorLayout
und eine funktionierendeAppBarLayout
erstellt wurden.
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 Scrolling-Informationen zwischen NestedScrollView
und AppBarLayout
zu teilen. Wenn NestedScrollView
nach oben scrollt, wird AppBarLayout
über die Änderung informiert. So implementieren Sie eine solche minimierbare Symbolleiste in Android – das Scrollen des Textes wird "koordiniert". mit der minimierbaren Kopfzeile.
Die Bewegungsszene, auf die @id/motion_layout
verweist, ähnelt der Bewegungsszene im letzten Schritt. Die Deklaration „OnSwipe
“ wurde jedoch entfernt, damit sie mit CoordinatorLayout
funktioniert.
- Führen Sie die App aus und fahren Sie mit Schritt 8 fort. Sie sehen, dass sich der Mond nicht bewegt, wenn Sie durch den Text scrollen.
Schritt 2: MotionLayout zum Scrollen animieren
- Damit die Ansicht
MotionLayout
scrollt, sobaldNestedScrollView
scrollt, fügen Siemotion:minHeight
undmotion:layout_scrollFlags
zumMotionLayout
hinzu.
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
MotionLayout
minimiert wird, wenn Sie nach oben scrollen. Die Animation wird jedoch noch nicht basierend auf dem Scrollverhalten fortgesetzt.
Schritt 3: Bewegung mit Code bewegen
Step8Activity.kt
öffnen . Bearbeite diecoordinateMotion()
-Funktion, umMotionLayout
über die Änderungen an 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 eine OnOffsetChangedListener
registriert, die jedes Mal aufgerufen wird, wenn der Nutzer mit dem aktuellen Scroll-Offset scrollt.
MotionLayout
unterstützt durch Festlegen des Attributs „progress“, den Wechsel zu suchen. Wenn Sie einen verticalOffset
-Wert in einen prozentualen Fortschritt umrechnen möchten, teilen Sie das Ergebnis durch den gesamten Scrollbereich.
Jetzt ausprobieren
- Stellen Sie die App noch einmal bereit und führen Sie die Animation in Schritt 8 aus. Sie sehen, dass
MotionLayout
die Animation basierend auf der Scrollposition fortsetzt.
Mit MotionLayout
können Sie benutzerdefinierte Animationen für dynamische minimierbare Symbolleisten erstellen. Mit einer KeyFrames
-Sequenz können Sie sehr ausdrucksstarke Effekte erzielen.
12. Glückwunsch
In diesem Codelab wurde die grundlegende API von MotionLayout
behandelt.
Weitere Beispiele für MotionLayout
in der Praxis finden Sie im offiziellen Beispiel. Weitere Informationen finden Sie in der 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 basierend auf der Uhrzeit animieren können. In den Beispielen finden Sie entsprechende Beispiele.
Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage zu den Codelabs für Fortgeschrittene mit Android in Kotlin.