Bewegung mit Federphysik animieren

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zur Verwendung von Animationen in Compose

Physikbasierte Bewegungen werden durch Kraft gesteuert. Die Federkraft ist eine solche Kraft, die Interaktivität und Bewegung steuert. Eine Federkraft hat die folgenden Eigenschaften: Dämpfung und Steifigkeit. Bei einer federbasierten Animation werden der Wert und die Geschwindigkeit auf Grundlage der Federkraft berechnet, die in jedem Frame angewendet wird.

Wenn die Animationen Ihrer App nur in eine Richtung verlangsamt werden sollen, sollten Sie stattdessen eine reibungsbasierte Fling-Animation verwenden.

Lebenszyklus einer federnden Animation

In einer federbasierten Animation können Sie mit der Klasse SpringForce die Steifigkeit der Feder, ihr Dämpfungsverhältnis und ihre Endposition anpassen. Sobald die Animation beginnt, werden der Animationswert und die Geschwindigkeit in jedem Frame durch die Federkraft aktualisiert. Die Animation wird fortgesetzt, bis die Federkraft ein Gleichgewicht erreicht.

Wenn Sie beispielsweise ein App-Symbol auf dem Display verschieben und es dann loslassen, indem Sie den Finger vom Symbol nehmen, wird das Symbol durch eine unsichtbare, aber vertraute Kraft an seinen ursprünglichen Platz zurückgezogen.

Abbildung 1 zeigt einen ähnlichen Federeffekt. Das Pluszeichen (+) in der Mitte des Kreises gibt die durch eine Berührung ausgeübte Kraft an.

Frühlingsrelease
Abbildung 1: Frühlings-Release-Effekt

Federnde Animation erstellen

So erstellen Sie eine Federanimation für Ihre Anwendung:

In den folgenden Abschnitten werden die allgemeinen Schritte zum Erstellen einer Federanimation im Detail beschrieben.

Supportbibliothek hinzufügen

Wenn Sie die auf Physik basierende Supportbibliothek verwenden möchten, müssen Sie sie Ihrem Projekt so hinzufügen:

  1. Öffnen Sie die Datei build.gradle für Ihr App-Modul.
  2. Fügen Sie die Support-Bibliothek dem Abschnitt dependencies hinzu.

    Groovy

            dependencies {
                def dynamicanimation_version = '1.0.0'
                implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version"
            }
            

    Kotlin

            dependencies {
                val dynamicanimation_version = "1.0.0"
                implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version")
            }
            

    Die aktuellen Versionen dieser Bibliothek finden Sie auf der Seite Versionen unter „Dynamicanimation“.

Federanimation erstellen

Mit der Klasse SpringAnimation können Sie eine Federanimation für ein Objekt erstellen. Um eine Federanimation zu erstellen, müssen Sie eine Instanz der Klasse SpringAnimation erstellen und ein Objekt, eine zu animierende Eigenschaft des Objekts und eine optionale Endposition der Feder angeben, an der die Animation enden soll.

Hinweis:Beim Erstellen einer Federanimation ist die endgültige Position der Feder optional. Sie muss jedoch vor dem Start der Animation definiert werden.

Kotlin

val springAnim = findViewById<View>(R.id.imageView).let { img ->
    // Setting up a spring animation to animate the view’s translationY property with the final
    // spring position at 0.
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f)
}

Java

final View img = findViewById(R.id.imageView);
// Setting up a spring animation to animate the view’s translationY property with the final
// spring position at 0.
final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);

Bei der federbasierten Animation werden Ansichten auf dem Bildschirm animiert, indem die tatsächlichen Attribute in den Ansichtsobjekten geändert werden. Die folgenden Ansichten sind im System verfügbar:

  • ALPHA: Stellt die Alphatransparenz in der Ansicht dar. Der Standardwert ist 1 (undurchsichtig). Ein Wert von 0 steht für vollständige Transparenz (nicht sichtbar).
  • TRANSLATION_X, TRANSLATION_Y und TRANSLATION_Z: Mit diesen Attributen wird die Position der Ansicht als Delta von der linken Koordinate, der oberen Koordinate und der Höhe des Layoutcontainers festgelegt.
  • ROTATION, ROTATION_X und ROTATION_Y: Mit diesen Attributen wird die Drehung in 2D (rotation-Attribut) und 3D um den Drehpunkt gesteuert.
  • SCROLL_X und SCROLL_Y: Diese Eigenschaften geben den Scroll-Offset der Quelle links und des oberen Rands in Pixel an. Außerdem wird die Position in Bezug darauf angegeben, wie weit die Seite gescrollt wurde.
  • SCALE_X und SCALE_Y: Mit diesen Eigenschaften wird die 2D-Skalierung einer Ansicht um ihren Drehpunkt gesteuert.
  • X, Y und Z: Dies sind grundlegende Hilfseigenschaften, mit denen die endgültige Position der Ansicht in ihrem Container beschrieben wird.

Listener registrieren

Die Klasse DynamicAnimation bietet zwei Listener: OnAnimationUpdateListener und OnAnimationEndListener. Diese Listener reagieren auf Aktualisierungen der Animation, z. B. wenn sich der Animationswert ändert und wenn die Animation beendet wird.

OnAnimationUpdateListener

Wenn Sie mehrere Ansichten animieren möchten, um eine verkettete Animation zu erstellen, können Sie OnAnimationUpdateListener so einrichten, dass jedes Mal ein Callback erfolgt, wenn sich die Property der aktuellen Ansicht ändert. Der Callback benachrichtigt die andere Ansicht, ihre Federposition basierend auf der Änderung der Property der aktuellen Ansicht zu aktualisieren. Führen Sie die folgenden Schritte aus, um den Listener zu registrieren:

  1. Rufen Sie die Methode addUpdateListener() auf und hängen Sie den Listener an die Animation an.

    Hinweis:Sie müssen den Update-Listener registrieren, bevor die Animation beginnt. Der Update-Listener sollte jedoch nur registriert werden, wenn Sie eine Aktualisierung des Animationswerts pro Frame benötigen. Ein Update-Listener verhindert, dass die Animation möglicherweise in einem separaten Thread ausgeführt wird.

  2. Überschreiben Sie die Methode onAnimationUpdate(), um den Aufrufer über die Änderung des aktuellen Objekts zu informieren. Der folgende Beispielcode veranschaulicht die allgemeine Verwendung von OnAnimationUpdateListener.

Kotlin

// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties
val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 ->
    SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to
            SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y)
}
val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 ->
    SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to
            SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y)
}

// Registering the update listener
anim1X.addUpdateListener { _, value, _ ->
    // Overriding the method to notify view2 about the change in the view1’s property.
    anim2X.animateToFinalPosition(value)
}

anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }

Java

// Creating two views to demonstrate the registration of the update listener.
final View view1 = findViewById(R.id.view1);
final View view2 = findViewById(R.id.view2);

// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties
final SpringAnimation anim1X = new SpringAnimation(view1,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim1Y = new SpringAnimation(view1,
    DynamicAnimation.TRANSLATION_Y);
final SpringAnimation anim2X = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim2Y = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_Y);

// Registering the update listener
anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

// Overriding the method to notify view2 about the change in the view1’s property.
    @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2X.animateToFinalPosition(value);
    }
});

anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

  @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2Y.animateToFinalPosition(value);
    }
});

OnAnimationEndListener

OnAnimationEndListener Benachrichtigt über das Ende einer Animation. Sie können den Listener so einrichten, dass er einen Callback empfängt, wenn die Animation den Gleichgewichtszustand erreicht oder abgebrochen wird. Führen Sie die folgenden Schritte aus, um den Listener zu registrieren:

  1. Rufen Sie die Methode addEndListener() auf und hängen Sie den Listener an die Animation an.
  2. Überschreiben Sie die onAnimationEnd()-Methode, um eine Benachrichtigung zu erhalten, wenn eine Animation den Gleichgewichtszustand erreicht oder abgebrochen wird.

Listener entfernen

Wenn Sie keine Rückrufe für Animationsaktualisierungen und Animationsende mehr erhalten möchten, rufen Sie die Methoden removeUpdateListener() bzw. removeEndListener() auf.

Startwert für die Animation festlegen

Rufen Sie die Methode setStartValue() auf und übergeben Sie den Startwert der Animation, um den Startwert der Animation festzulegen. Wenn Sie den Startwert nicht festlegen, wird der aktuelle Wert der Objekteigenschaft als Startwert verwendet.

Wertebereich für Animation festlegen

Sie können die Mindest- und Höchstwerte für die Animation festlegen, wenn Sie den Eigenschaftswert auf einen bestimmten Bereich beschränken möchten. Außerdem können Sie damit den Bereich steuern, wenn Sie Eigenschaften animieren, die einen intrinsischen Bereich haben, z. B. Alpha (von 0 bis 1).

  • Rufen Sie zum Festlegen des Mindestwerts die Methode setMinValue() auf und übergeben Sie den Mindestwert der Eigenschaft.
  • Rufen Sie die Methode setMaxValue() auf und übergeben Sie den Höchstwert der Eigenschaft, um den Höchstwert festzulegen.

Beide Methoden geben die Animation zurück, für die der Wert festgelegt wird.

Hinweis:Wenn Sie den Startwert festgelegt und einen Animationswertbereich definiert haben, muss der Startwert innerhalb des Mindest- und Höchstwertbereichs liegen.

Startgeschwindigkeit festlegen

Mit „Startgeschwindigkeit“ wird die Geschwindigkeit definiert, mit der sich die Animationseigenschaft am Anfang der Animation ändert. Die standardmäßige Startgeschwindigkeit ist auf null Pixel pro Sekunde festgelegt. Sie können die Geschwindigkeit entweder mit der Geschwindigkeit von Touch-Gesten oder mit einem festen Wert als Startgeschwindigkeit festlegen. Wenn Sie einen festen Wert angeben möchten, empfehlen wir, den Wert in dp pro Sekunde zu definieren und dann in Pixel pro Sekunde umzurechnen. Wenn Sie den Wert in dp pro Sekunde definieren, ist die Geschwindigkeit unabhängig von Dichte und Formfaktoren. Weitere Informationen zum Umrechnen von Werten in Pixel pro Sekunde finden Sie im Abschnitt dp pro Sekunde in Pixel pro Sekunde umrechnen.

Rufen Sie die Methode setStartVelocity() auf und übergeben Sie die Geschwindigkeit in Pixel pro Sekunde, um die Geschwindigkeit festzulegen. Die Methode gibt das Federkraftobjekt zurück, für das die Geschwindigkeit festgelegt ist.

Hinweis:Verwenden Sie die Klassenmethoden GestureDetector.OnGestureListener oder VelocityTracker, um die Geschwindigkeit von Touch-Gesten abzurufen und zu berechnen.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        
        // Compute velocity in the unit pixel/second
        vt.computeCurrentVelocity(1000)
        val velocity = vt.yVelocity
        setStartVelocity(velocity)
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);

// Compute velocity in the unit pixel/second
vt.computeCurrentVelocity(1000);
float velocity = vt.getYVelocity();
anim.setStartVelocity(velocity);

dp pro Sekunde in Pixel pro Sekunde umrechnen

Die Geschwindigkeit einer Feder muss in Pixel pro Sekunde angegeben werden. Wenn Sie einen festen Wert als Startgeschwindigkeit angeben möchten, geben Sie den Wert in dp pro Sekunde an und wandeln Sie ihn dann in Pixel pro Sekunde um. Verwenden Sie für die Konvertierung die Methode applyDimension() aus der Klasse TypedValue. Hier ein Beispielcode:

Kotlin

val pixelPerSecond: Float =
    TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)

Java

float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());

Federeigenschaften festlegen

Die Klasse SpringForce definiert die Getter- und Setter-Methoden für die einzelnen Federeigenschaften wie Dämpfungsverhältnis und Steifigkeit. Zum Festlegen der Spring-Eigenschaften müssen Sie entweder das Spring-Force-Objekt abrufen oder eine benutzerdefinierte Spring-Force erstellen, für die Sie die Eigenschaften festlegen können. Weitere Informationen zum Erstellen einer benutzerdefinierten Federkraft finden Sie im Abschnitt Benutzerdefinierte Federkraft erstellen.

Tipp:Bei Verwendung der Setter-Methoden können Sie eine Methodenverkettung erstellen, da alle Setter-Methoden das Federkraftobjekt zurückgeben.

Dämpfungsverhältnis

Das Dämpfungsverhältnis beschreibt eine allmähliche Verringerung der Schwingung einer Feder. Mit dem Dämpfungsverhältnis können Sie festlegen, wie schnell die Schwingungen von einem Sprung zum nächsten abklingen. Es gibt vier verschiedene Möglichkeiten, eine Feder zu dämpfen:

  • Eine Überdämpfung tritt auf, wenn das Dämpfungsverhältnis größer als 1 ist. Dadurch kehrt das Objekt sanft in die Ruheposition zurück.
  • Kritische Dämpfung tritt auf, wenn das Dämpfungsverhältnis gleich 1 ist. So kann das Objekt in kürzester Zeit in die Ruheposition zurückkehren.
  • Eine Unterdämpfung tritt auf, wenn das Dämpfungsverhältnis kleiner als 1 ist. Das Objekt kann die Ruheposition mehrmals überschwingen und erreicht sie dann allmählich.
  • Eine ungedämpfte Reaktion tritt auf, wenn das Dämpfungsverhältnis gleich null ist. Dadurch schwingt das Objekt unendlich lange.

So fügen Sie der Feder das Dämpfungsverhältnis hinzu:

  1. Rufen Sie die Methode getSpring() auf, um die Feder abzurufen, der das Dämpfungsverhältnis hinzugefügt werden soll.
  2. Rufen Sie die Methode setDampingRatio() auf und übergeben Sie das Dämpfungsverhältnis, das Sie der Feder hinzufügen möchten. Die Methode gibt das Federkraftobjekt zurück, für das das Dämpfungsverhältnis festgelegt ist.

    Hinweis:Das Dämpfungsverhältnis muss eine nicht negative Zahl sein. Wenn Sie das Dämpfungsverhältnis auf null setzen, erreicht die Feder nie die Ruheposition. Mit anderen Worten: Es schwingt unendlich lange.

Die folgenden Dämpfungsverhältnis-Konstanten sind im System verfügbar:

Abbildung 2: Hohe Absprungrate

Abbildung 3: Mittlere Absprungrate

Abbildung 4: Geringe Absprungrate

Abbildung 5: Keine Rücksendung

Das Standarddämpfungsverhältnis ist auf DAMPING_RATIO_MEDIUM_BOUNCY festgelegt.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        
        // Setting the damping ratio to create a low bouncing effect.
        spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
        
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);

// Setting the damping ratio to create a low bouncing effect.
anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY);

Steifheit

Die Steifigkeit definiert die Federkonstante, die die Stärke der Feder misst. Eine steife Feder übt mehr Kraft auf das angebrachte Objekt aus, wenn sie sich nicht in der Ruheposition befindet. So fügen Sie die Steifigkeit der Feder hinzu:

  1. Rufen Sie die Methode getSpring() auf, um die Feder abzurufen, die die Steifigkeit hinzufügen soll.
  2. Rufen Sie die Methode setStiffness() auf und übergeben Sie den Steifigkeitswert, den Sie der Feder hinzufügen möchten. Die Methode gibt das Federkraftobjekt zurück, für das die Steifigkeit festgelegt ist.

    Hinweis:Die Steifigkeit muss eine positive Zahl sein.

Die folgenden Steifigkeitskonstanten sind im System verfügbar:

Abbildung 6: Hohe Steifigkeit

Abbildung 7: Mittlere Steifigkeit

Abbildung 8: Geringe Steifigkeit

Abbildung 9: Sehr geringe Steifigkeit

Die Standardsteifigkeit ist auf STIFFNESS_MEDIUM festgelegt.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        
        // Setting the spring with a low stiffness.
        spring.stiffness = SpringForce.STIFFNESS_LOW
        
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);

// Setting the spring with a low stiffness.
anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW);

Benutzerdefinierte Federkraft erstellen

Sie können eine benutzerdefinierte Federkraft erstellen, anstatt die Standardfederkraft zu verwenden. Mit der benutzerdefinierten Federkraft können Sie dieselbe Federkraftinstanz für mehrere Federanimationen verwenden. Nachdem Sie die Federkraft erstellt haben, können Sie Eigenschaften wie Dämpfungsverhältnis und Steifigkeit festlegen.

  1. Erstellen Sie ein SpringForce-Objekt.

    SpringForce force = new SpringForce();

  2. Weisen Sie die Attribute durch Aufrufen der entsprechenden Methoden zu. Sie können auch eine Methodenverkettung erstellen.

    force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);

  3. Rufen Sie die Methode setSpring() auf, um die Feder für die Animation festzulegen.

    setSpring(force);

Animation starten

Es gibt zwei Möglichkeiten, eine Federanimation zu starten: durch Aufrufen von start() oder durch Aufrufen der Methode animateToFinalPosition(). Beide Methoden müssen im Hauptthread aufgerufen werden.

Die Methode animateToFinalPosition() führt zwei Aufgaben aus:

  • Legt die Endposition der Feder fest.
  • Startet die Animation, falls sie noch nicht gestartet wurde.

Da mit der Methode die Endposition der Feder aktualisiert und die Animation bei Bedarf gestartet wird, können Sie diese Methode jederzeit aufrufen, um den Verlauf einer Animation zu ändern. Bei einer verketteten Federanimation hängt die Animation einer Ansicht beispielsweise von einer anderen Ansicht ab. Für eine solche Animation ist es praktischer, die Methode animateToFinalPosition() zu verwenden. Wenn Sie diese Methode in einer verketteten Spring-Animation verwenden, müssen Sie sich keine Sorgen machen, ob die Animation, die Sie als Nächstes aktualisieren möchten, gerade ausgeführt wird.

Abbildung 10 zeigt eine verkettete Federanimation, bei der die Animation einer Ansicht von einer anderen Ansicht abhängt.

Verkettete Frühjahrsdemo
Abbildung 10. Demo für verkettete Federn

Wenn Sie die Methode animateToFinalPosition() verwenden möchten, rufen Sie die Methode animateToFinalPosition() auf und übergeben Sie die Ruheposition der Feder. Sie können die Ruheposition der Feder auch festlegen, indem Sie die Methode setFinalPosition() aufrufen.

Mit der Methode start() wird der Attributwert nicht sofort auf den Startwert gesetzt. Der Eigenschaftswert ändert sich bei jedem Animationsimpuls, der vor dem Zeichenvorgang erfolgt. Die Änderungen werden daher im nächsten Frame berücksichtigt, als ob die Werte sofort festgelegt würden.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        
        // Starting the animation
        start()
        
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);

// Starting the animation
anim.start();

Animation abbrechen

Sie können die Animation abbrechen oder zum Ende springen. Eine ideale Situation, in der Sie die Animation abbrechen oder zum Ende springen müssen, ist, wenn eine Nutzerinteraktion erfordert, dass die Animation sofort beendet wird. Dies geschieht meistens, wenn ein Nutzer eine App abrupt beendet oder die Ansicht unsichtbar wird.

Es gibt zwei Methoden, mit denen Sie die Animation beenden können. Die Methode cancel() beendet die Animation am aktuellen Wert. Die Methode skipToEnd() springt zum Endwert und beendet die Animation dann.

Bevor Sie die Animation beenden können, müssen Sie zuerst den Zustand der Feder prüfen. Wenn der Zustand nicht gedämpft ist, kann die Animation die Ruheposition nie erreichen. Rufen Sie die Methode canSkipToEnd() auf, um den Status der Feder zu prüfen. Wenn die Feder gedämpft ist, gibt die Methode true zurück, andernfalls false.

Sobald Sie den Status der Feder kennen, können Sie eine Animation mit der Methode skipToEnd() oder cancel() beenden. Die Methode cancel() muss nur im Hauptthread aufgerufen werden.

Hinweis:Im Allgemeinen führt die Methode skipToEnd() zu einem visuellen Sprung.