Android für Fortgeschrittene in Kotlin 03.2: Animation mit MotionLayout

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 zu ConstraintLayout finden Sie im Codelab für das Einschränkungslayout.

Aufgabe

  • Animation mit ConstraintSets und MotionLayout 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 von ConstraintLayout ist. Sie geben im MotionLayout-Tag alle Ansichten an, die animiert werden sollen.
  • Ein MotionScene,, also eine XML-Datei, die eine Animation für MotionLayout. beschreibt
  • Ein Transition,, das Teil des MotionScene 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

  1. Öffnen Sie activity_step1.xml. in res/layout. Hier sehen Sie eine ConstraintLayout mit einem einzelnen ImageView 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.

  1. Ö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.

a2beea710c2decb7.png

  1. Klicken Sie in der Designoberfläche mit der rechten Maustaste auf die Vorschau und wählen Sie Convert to MotionLayout aus.

4fa936a98a8393b9.png

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.

66d0e80d5ab4daf8.png

Der Bewegungseditor enthält drei neue UI-Elemente:

  1. Ü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 zwischen start und end auswählen, indem du auf den Pfeil dazwischen klickst.
  2. 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.
  3. 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.

  1. Im Übersichtsbereich das ConstraintSet start auswählen

6e57661ed358b860.png

  1. Wählen Sie im Auswahlbereich die Option red_star aus. Aktuell wird die Quelle layout angezeigt. Das bedeutet, dass sie in dieser ConstraintSet nicht eingeschränkt ist. Verwenden Sie das Stiftsymbol oben rechts, um Einschränkung erstellen zu erstellen.

f9564c574b86ea8.gif

  1. Prüfen Sie, ob red_star als Quelle start angezeigt wird, wenn start ConstraintSet im Übersichtsbereich ausgewählt ist.
  2. Fügen Sie im Bereich „Attribute“ mit der Option red_star in der start ConstraintSet oben eine Einschränkung hinzu und klicken Sie zuerst auf die blauen +-Schaltflächen.

2fce076cd7b04bd.png

  1. Ö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.

  1. Wählen Sie im Übersichtsbereich die ConstraintSet end aus.

346e1248639b6f1e.png

  1. Führen Sie dieselben Schritte wie zuvor aus, um ein Constraint für red_star in der end ConstraintSet hinzuzufügen.
  2. Um diesen Schritt mit dem Bewegungseditor abzuschließen, fügen Sie bottom und end eine Einschränkung hinzu, indem Sie auf die blauen +-Schaltflächen klicken.

fd33c779ff83c80a.png

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

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

dff9ecdc1f4a0740.gif

Animation:Video der Wiedergabe einer Übergangsvorschau im Motion Editor

  1. Öffnen Sie den Bewegungs-Editor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen start und end klicken.

1dc541ae8c43b250.png

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

a0fd2593384dfb36.png

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.

  1. Öffnen Sie den Bewegungs-Editor und wählen Sie den Übergang aus, indem Sie im Übersichtsbereich auf den Pfeil zwischen Start und Ende klicken.

b6f94b344ce65290.png

  1. Klicken Sie in der Symbolleiste des Übersichtssteuerfelds auf 699f7ae04024ccf6.png Klick- oder Wisch-Handler erstellen . Dadurch wird ein Handler hinzugefügt, mit dem ein Übergang gestartet wird.
  2. Wählen Sie im Pop-up die Option Click Handler (Klick-Handler) aus.

ccf92d06335105fe.png

  1. Ändern Sie View To Click in red_star.

b0d3f0c970604f01.png

  1. Klicken Sie auf Add (Hinzufügen). Der Klick-Handler wird durch einen kleinen Punkt auf dem Übergang im Motion Editor dargestellt.

cec3913e67fb4105.png

  1. Wählen Sie den Übergang im Übersichtsbereich aus und fügen Sie dem gerade im Attributbereich hinzugefügten OnClick-Handler das clickAction-Attribut toggle hinzu.

9af6fc60673d093d.png

  1. Ö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 von toggle wechselt beim Klicken zwischen Start- und Endstatus. Weitere Optionen für clickAction finden Sie in der Dokumentation.
  1. 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.

7ba88af963fdfe10.gif

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

  1. Öffnen Sie dazu die Layoutdatei activity_step2.xml, in der bereits MotionLayout 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

  1. Öffnen Sie die Bewegungsszene xml/step2.xml, um die Animation zu definieren.
  2. 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 den alpha-Wert 0.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

  1. Definieren Sie die Endbindung so, dass alle drei Sterne mithilfe einer Kette unter @id/credits positioniert werden. Außerdem wird der Endwert von alpha der linken und rechten Sterne auf 1.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.

  1. 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. In MotionLayout 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

  1. Führen Sie die App noch einmal aus und öffnen Sie Schritt 2. Sie sehen die Animation.
  2. 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.

fefcdd690a0dcaec.gif

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

  1. Öffnen Sie layout/activity_step3.xml und xml/step3.xml, um das vorhandene Layout und die vorhandene Bewegungsszene zu sehen. ImageView und TextView zeigen den Mond und die Quellenangaben an.
  2. Öffnen Sie die Datei mit der Bewegungsszene (xml/step3.xml). Sie sehen, dass eine Transition von @id/start bis @id/end definiert ist. Bei der Animation wird das Mondbild mithilfe von zwei ConstraintSets von links unten nach rechts unten auf dem Bildschirm verschoben. Während der Mond bewegt wird, wird der Beitragstext von alpha="0.0" bis alpha="1.0" eingeblendet.
  3. 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.

  1. Wenn Sie Debugging-Pfade aktivieren möchten, öffnen Sie layout/activity_step3.xml und fügen Sie dem MotionLayout-Tag motion: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.

23bbb604f456f65c.png

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

  1. Öffne xml/step3.xml und füge der Szene ein KeyPosition hinzu. Das KeyPosition-Tag wird innerhalb des Transition-Tags platziert.

eae4dae9a12d0410.png

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 dieses KeyPosition 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 dieser KeyPosition den Pfad ändert.
  • Mit keyPositionType ändert KeyPosition den Pfad. Es kann entweder parentRelative, pathRelative oder deltaRelative sein (wie im nächsten Schritt erläutert).
  • percentX | percentY gibt an, wie stark der Pfad bei framePosition 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.

46b179c01801f19e.gif

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?

1c7cf779931e45cc.gif

<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

a7b7568d46d9dec7.png

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

5680bf553627416c.png

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

f3aaadaac8b4a93f.png

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, welche framePosition ein bestimmter Punkt im Pfad erreicht wird. Ein KeyPosition bei framePosition="50" mit einem percentX="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 erzeugt deltaRelative 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.

  1. Öffnen Sie xml/step4.xml. Sie enthält dieselben Aufrufe und die KeyFrame, die Sie im letzten Schritt hinzugefügt haben.
  2. 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.

500b5ac2db48ef87.png

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

  1. 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 der KeyFrameSet 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.

cd9faaffde3dfef.png

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

  1. Ö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.
  2. Damit der Mond größer angezeigt und gedreht werden kann, fügen Sie zwei KeyAttribute-Tags in die KeyFrameSet bei keyFrame="50" und keyFrame="100" ein.

bbae524a2898569.png

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.

  1. Wenn Sie die Anzeige von Gutschriften verzögern möchten, definieren Sie eine weitere KeyAttribute, die dafür sorgt, dass alpha bis zum keyPosition="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

  1. 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 der KeyFrameSet angegeben wurde.

2f4bfdd681c1fa98.gif

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.

5fb6792126a09fda.gif

Benutzerdefinierte Attribute definieren

  1. Öffnen Sie zunächst xml/step6.xml. Es enthält dieselbe Animation, die Sie im letzten Schritt erstellt haben.
  2. Damit sich die Farbe des Mondes ändert, musst du zwei KeyAttribute mit einem CustomAttribute in die KeyFrameSet bei keyFrame="0", keyFrame="50" und keyFrame="100". addieren

214699d5fdd956da.png

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 wird setColorFilter am Drawable 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

  1. 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 der KeyFrameSet angegeben wurde.

5fb6792126a09fda.gif

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

  1. Öffnen Sie xml/step7.xml und suchen Sie die vorhandene OnSwipe-Deklaration.

step7.xml

<!-- Fix OnSwipe by changing touchAnchorSide 

<OnSwipe
       motion:touchAnchorId="@id/moon"
       motion:touchAnchorSide="bottom"
/>
  1. 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.

ed96e3674854a548.gif

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?

56cd575c5c77eddd.png

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.

  1. Wenn diese Animation Touch-Events folgen soll, ändere die touchAnchorSide zu right.

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.

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

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

5458dff382261427.gif

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

  1. Öffne layout/activity_step8.xml, um loszulegen.
  2. Sie sehen in layout/activity_step8.xml, dass bereits eine funktionierende CoordinatorLayout und eine funktionierende AppBarLayout 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.

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

  1. Damit die Ansicht MotionLayout scrollt, sobald NestedScrollView scrollt, fügen Sie motion:minHeight und motion:layout_scrollFlags zum MotionLayout 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"  >
  1. 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

  1. Step8Activity.kt öffnen . Bearbeite die coordinateMotion()-Funktion, um MotionLayout ü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

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

ee5ce4d9e33a59ca.gif

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.