Attributanimation – Übersicht

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

Das Property-Animationssystem ist ein robustes Framework, mit dem Sie fast alles animieren können. Sie können eine Animation definieren, um eine beliebige Objekteigenschaft im Zeitverlauf zu ändern, unabhängig davon, ob sie auf dem Bildschirm gerendert wird oder nicht. Bei einer Property-Animation wird der Wert einer Property (ein Feld in einem Objekt) über einen bestimmten Zeitraum hinweg geändert. Wenn Sie etwas animieren möchten, geben Sie die Objekteigenschaft an, die animiert werden soll, z. B. die Position eines Objekts auf dem Bildschirm, die Dauer der Animation und die Werte, zwischen denen animiert werden soll.

Mit dem System für Property-Animationen können Sie die folgenden Merkmale einer Animation definieren:

  • Dauer: Sie können die Dauer einer Animation angeben. Die Standardlänge beträgt 300 ms.
  • Zeitinterpolation: Sie können angeben, wie die Werte für die Eigenschaft als Funktion der aktuellen verstrichenen Zeit der Animation berechnet werden.
  • Anzahl der Wiederholungen und Verhalten: Sie können festlegen, ob eine Animation wiederholt werden soll, wenn sie das Ende eines Zeitraums erreicht, und wie oft sie wiederholt werden soll. Sie können auch festlegen, ob die Animation rückwärts wiedergegeben werden soll. Wenn Sie diese Option auf „Rückwärts“ setzen, wird die Animation wiederholt vorwärts und rückwärts abgespielt, bis die Anzahl der Wiederholungen erreicht ist.
  • Animatorsets: Sie können Animationen in logischen Sets gruppieren, die gleichzeitig, nacheinander oder nach bestimmten Verzögerungen abgespielt werden.
  • Verzögerung bei der Aktualisierung von Frames: Sie können festlegen, wie oft die Frames Ihrer Animation aktualisiert werden sollen. Standardmäßig wird alle 10 ms aktualisiert. Die Geschwindigkeit, mit der Ihre Anwendung Frames aktualisieren kann, hängt jedoch letztendlich davon ab, wie stark das System insgesamt ausgelastet ist und wie schnell das System den zugrunde liegenden Timer bedienen kann.

Ein vollständiges Beispiel für die Property-Animation finden Sie in der Klasse ChangeColor im CustomTransition-Beispiel auf GitHub.

Funktionsweise der Attributanimation

Sehen wir uns zuerst an einem einfachen Beispiel an, wie eine Animation funktioniert. Abbildung 1 zeigt ein hypothetisches Objekt, dessen x-Eigenschaft animiert wird. Diese Eigenschaft gibt die horizontale Position des Objekts auf einem Bildschirm an. Die Dauer der Animation ist auf 40 ms und die zurückzulegende Entfernung auf 40 Pixel festgelegt. Alle 10 ms, was der standardmäßigen Aktualisierungsrate für Frames entspricht, bewegt sich das Objekt horizontal um 10 Pixel. Nach 40 ms wird die Animation beendet und das Objekt befindet sich an der horizontalen Position 40. Dies ist ein Beispiel für eine Animation mit linearer Interpolation. Das Objekt bewegt sich also mit konstanter Geschwindigkeit.

Abbildung 1. Beispiel für eine lineare Animation

Sie können auch Animationen mit nicht linearer Interpolation angeben. Abbildung 2 zeigt ein hypothetisches Objekt, das am Anfang der Animation beschleunigt und am Ende der Animation verlangsamt wird. Das Objekt bewegt sich immer noch 40 Pixel in 40 ms, aber nicht linear. Zu Beginn beschleunigt diese Animation bis zur Hälfte und verlangsamt sich dann bis zum Ende. Wie in Abbildung 2 zu sehen ist, ist die zurückgelegte Strecke am Anfang und Ende der Animation geringer als in der Mitte.

Abbildung 2: Beispiel für eine nicht lineare Animation

Sehen wir uns genauer an, wie die wichtigen Komponenten des Property-Animationssystems Animationen wie die oben gezeigten berechnen. Abbildung 3 zeigt, wie die Hauptklassen zusammenarbeiten.

Abbildung 3: So werden Animationen berechnet

Das ValueAnimator-Objekt verfolgt das Timing Ihrer Animation, z. B. wie lange die Animation schon läuft und den aktuellen Wert der animierten Eigenschaft.

Die ValueAnimator kapselt eine TimeInterpolator, die die Animationsinterpolation definiert, und eine TypeEvaluator, die definiert, wie Werte für die animierte Eigenschaft berechnet werden. In Abbildung 2 wäre TimeInterpolator beispielsweise AccelerateDecelerateInterpolator und TypeEvaluator wäre IntEvaluator.

Um eine Animation zu starten, erstellen Sie ein ValueAnimator und geben Sie die Start- und Endwerte für das Attribut an, das Sie animieren möchten, sowie die Dauer der Animation. Wenn Sie start() aufrufen, beginnt die Animation. Während der gesamten Animation berechnet ValueAnimator einen vergangenen Bruchteil zwischen 0 und 1 basierend auf der Dauer der Animation und der verstrichenen Zeit. Der verstrichene Bruchteil gibt den Prozentsatz der Zeit an, die seit Beginn der Animation vergangen ist. 0 bedeutet 0 % und 1 bedeutet 100%. In Abbildung 1 wäre der verstrichene Anteil bei t = 10 ms beispielsweise 0, 25, da die Gesamtdauer t = 40 ms beträgt.

Wenn ValueAnimator einen verstrichenen Bruchteil berechnet hat, wird die aktuell festgelegte TimeInterpolator aufgerufen, um einen interpolierten Bruchteil zu berechnen. Ein interpolierter Bruchteil bildet den verstrichenen Bruchteil auf einen neuen Bruchteil ab, der die festgelegte Zeitinterpolation berücksichtigt. In Abbildung 2 ist der interpolierte Bruchteil (ca. 0,15) beispielsweise geringer als der verstrichene Bruchteil (0,25) bei t = 10 ms, da die Animation langsam beschleunigt wird. In Abbildung 1 ist der interpolierte Bruchteil immer gleich dem verstrichenen Bruchteil.

Wenn der interpolierte Bruchteil berechnet wird, ruft ValueAnimator die entsprechende TypeEvaluator auf, um den Wert der animierten Eigenschaft basierend auf dem interpolierten Bruchteil, dem Startwert und dem Endwert der Animation zu berechnen. In Abbildung 2 betrug der interpolierte Bruchteil beispielsweise 0,15 bei t = 10 ms. Der Wert für die Eigenschaft zu diesem Zeitpunkt wäre also 0,15 × (40 – 0) oder 6.

Unterschiede zwischen Attribut- und Ansichtsanimation

Das System für Ansichtsanimationen bietet die Möglichkeit, nur View-Objekte zu animieren. Wenn Sie also Nicht-View-Objekte animieren möchten, müssen Sie dazu eigenen Code implementieren. Das System für Ansichtsanimationen ist auch insofern eingeschränkt, als es nur wenige Aspekte eines View-Objekts für die Animation verfügbar macht, z. B. die Skalierung und Drehung einer Ansicht, nicht aber die Hintergrundfarbe.

Ein weiterer Nachteil des View-Animationssystems besteht darin, dass nur die Position geändert wurde, an der die View gezeichnet wurde, nicht die View selbst. Wenn Sie beispielsweise eine Schaltfläche animiert haben, sodass sie sich über den Bildschirm bewegt, wird die Schaltfläche korrekt gezeichnet. Die tatsächliche Position, an der Sie auf die Schaltfläche klicken können, ändert sich jedoch nicht. Sie müssen also eine eigene Logik implementieren, um dies zu berücksichtigen.

Mit dem Property-Animationssystem werden diese Einschränkungen vollständig aufgehoben. Sie können jede Eigenschaft eines beliebigen Objekts (Views und Nicht-Views) animieren und das Objekt selbst wird tatsächlich geändert. Das Attributanimationssystem ist auch robuster in der Art und Weise, wie Animationen ausgeführt werden. Im Wesentlichen weisen Sie Animatoren den Attributen zu, die Sie animieren möchten, z. B. Farbe, Position oder Größe. Außerdem können Sie Aspekte der Animation definieren, z. B. Interpolation und Synchronisierung mehrerer Animatoren.

Das System für Ansichtsanimationen ist jedoch schneller einzurichten und erfordert weniger Code. Wenn die Ansichtsanimation alles erledigt, was Sie benötigen, oder wenn Ihr vorhandener Code bereits wie gewünscht funktioniert, müssen Sie das Property-Animationssystem nicht verwenden. Es kann auch sinnvoll sein, beide Animationssysteme für verschiedene Situationen zu verwenden, wenn der Anwendungsfall eintritt.

API-Übersicht

Die meisten APIs des Property-Animationssystems finden Sie unter android.animation. Da im View-Animationssystem bereits viele Interpolatoren in android.view.animation definiert sind, können Sie diese Interpolatoren auch im Property-Animationssystem verwenden. In den folgenden Tabellen werden die Hauptkomponenten des Property-Animationssystems beschrieben.

Die Klasse Animator bietet die grundlegende Struktur zum Erstellen von Animationen. Normalerweise verwenden Sie diese Klasse nicht direkt, da sie nur minimale Funktionen bietet, die erweitert werden müssen, um die Animation von Werten vollständig zu unterstützen. Die folgenden abgeleiteten Klassen erweitern Animator:

Tabelle 1. Animator*innen

Klasse Beschreibung
ValueAnimator Die Haupt-Timing-Engine für die Property-Animation, die auch die Werte für die zu animierende Property berechnet. Sie enthält alle Hauptfunktionen, mit denen Animationswerte berechnet werden, sowie die Zeitangaben für jede Animation, Informationen dazu, ob eine Animation wiederholt wird, Listener, die Aktualisierungsereignisse empfangen, und die Möglichkeit, benutzerdefinierte Typen für die Auswertung festzulegen. Das Animieren von Attributen besteht aus zwei Teilen: dem Berechnen der animierten Werte und dem Festlegen dieser Werte für das Objekt und das Attribut, das animiert wird. ValueAnimator führt den zweiten Teil nicht aus. Sie müssen also auf Aktualisierungen von Werten warten, die von ValueAnimator berechnet werden, und die Objekte, die Sie animieren möchten, mit Ihrer eigenen Logik ändern. Weitere Informationen finden Sie im Abschnitt Animieren mit ValueAnimator.
ObjectAnimator Eine Unterklasse von ValueAnimator, mit der Sie ein Zielobjekt und eine zu animierende Objekteigenschaft festlegen können. Diese Klasse aktualisiert die Eigenschaft entsprechend, wenn sie einen neuen Wert für die Animation berechnet. Sie sollten ObjectAnimator verwenden, da es die Animation von Werten für Zielobjekte erheblich vereinfacht. Manchmal möchten Sie ValueAnimator jedoch direkt verwenden, da für ObjectAnimator einige zusätzliche Einschränkungen gelten, z. B. dass bestimmte Accessormethoden für das Zielobjekt vorhanden sein müssen.
AnimatorSet Bietet einen Mechanismus zum Gruppieren von Animationen, damit sie in Bezug zueinander ausgeführt werden. Sie können festlegen, dass Animationen gleichzeitig, nacheinander oder nach einer bestimmten Verzögerung abgespielt werden. Weitere Informationen finden Sie im Abschnitt Mehrere Animationen mit Animator-Sets choreografieren.

Evaluatoren teilen dem Property-Animationssystem mit, wie Werte für eine bestimmte Property berechnet werden sollen. Sie verwenden die Zeitsteuerungsdaten, die von einer Animator-Klasse bereitgestellt werden, den Start- und Endwert der Animation und berechnen anhand dieser Daten die animierten Werte der Eigenschaft. Das System für Attributanimationen bietet die folgenden Evaluatoren:

Tabelle 2 Bewerter

Klasse/Benutzeroberfläche Beschreibung
IntEvaluator Der Standard-Evaluator zum Berechnen von Werten für int-Properties.
FloatEvaluator Der Standard-Evaluator zum Berechnen von Werten für float-Properties.
ArgbEvaluator Der Standard-Evaluator zum Berechnen von Werten für Farbeigenschaften, die als Hexadezimalwerte dargestellt werden.
TypeEvaluator Eine Schnittstelle, mit der Sie einen eigenen Evaluator erstellen können. Wenn Sie eine Objekteigenschaft animieren, die kein int, float oder keine Farbe ist, müssen Sie die TypeEvaluator-Schnittstelle implementieren, um anzugeben, wie die animierten Werte der Objekteigenschaft berechnet werden sollen. Sie können auch ein benutzerdefiniertes TypeEvaluator für int, float und Farbwerte angeben, wenn Sie diese Typen anders als das Standardverhalten verarbeiten möchten. Weitere Informationen zum Schreiben eines benutzerdefinierten Evaluators finden Sie im Abschnitt TypeEvaluator verwenden.

Ein Zeitinterpolator definiert, wie bestimmte Werte in einer Animation als Funktion der Zeit berechnet werden. Sie können beispielsweise festlegen, dass Animationen linear über die gesamte Animation hinweg erfolgen sollen. Das bedeutet, dass sich die Animation die ganze Zeit gleichmäßig bewegt. Sie können aber auch festlegen, dass Animationen nichtlineare Zeit verwenden sollen, z. B. am Anfang beschleunigen und am Ende der Animation verlangsamen. In Tabelle 3 werden die Interpolatoren beschrieben, die in android.view.animation enthalten sind. Wenn keiner der bereitgestellten Interpolatoren Ihren Anforderungen entspricht, können Sie die TimeInterpolator-Schnittstelle implementieren und einen eigenen erstellen. Weitere Informationen zum Schreiben eines benutzerdefinierten Interpolators finden Sie unter Interpolatoren verwenden.

Tabelle 3 Interpolator

Klasse/Benutzeroberfläche Beschreibung
AccelerateDecelerateInterpolator Ein Interpolator, dessen Änderungsrate langsam beginnt und endet, aber in der Mitte beschleunigt.
AccelerateInterpolator Ein Interpolator, dessen Änderungsrate langsam beginnt und dann zunimmt.
AnticipateInterpolator Ein Interpolator, dessen Änderung rückwärts beginnt und dann nach vorn schnellt.
AnticipateOvershootInterpolator Ein Interpolator, dessen Änderung rückwärts beginnt, nach vorn schnellt und den Zielwert überschreitet und dann schließlich zum Endwert zurückkehrt.
BounceInterpolator Ein Interpolator, dessen Änderung am Ende zurückspringt.
CycleInterpolator Ein Interpolator, dessen Animation sich eine bestimmte Anzahl von Zyklen lang wiederholt.
DecelerateInterpolator Ein Interpolator, dessen Änderungsrate schnell beginnt und dann abnimmt.
LinearInterpolator Ein Interpolator, dessen Änderungsrate konstant ist.
OvershootInterpolator Ein Interpolator, dessen Änderung nach vorn springt und den letzten Wert überschreitet, dann aber wieder zurückkehrt.
TimeInterpolator Eine Schnittstelle, mit der Sie einen eigenen Interpolator implementieren können.

Mit ValueAnimator animieren

Mit der Klasse ValueAnimator können Sie Werte eines bestimmten Typs für die Dauer einer Animation animieren, indem Sie eine Reihe von int-, float- oder Farbwerte angeben, die animiert werden sollen. Sie erhalten ein ValueAnimator-Objekt, indem Sie eine der zugehörigen Factory-Methoden aufrufen: ofInt(), ofFloat() oder ofObject(). Beispiel:

Kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

In diesem Code beginnt die ValueAnimator-Funktion mit der Berechnung der Werte der Animation zwischen 0 und 100 für eine Dauer von 1.000 ms, wenn die start()-Methode ausgeführt wird.

Sie können auch einen benutzerdefinierten Typ für die Animation angeben:

Kotlin

ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

In diesem Code beginnt ValueAnimator mit der Berechnung der Werte der Animation zwischen startPropertyValue und endPropertyValue. Dabei wird die von MyTypeEvaluator bereitgestellte Logik für eine Dauer von 1.000 ms verwendet, wenn die Methode start() ausgeführt wird.

Sie können die Werte der Animation verwenden, indem Sie dem ValueAnimator-Objekt ein AnimatorUpdateListener hinzufügen, wie im folgenden Code gezeigt:

Kotlin

ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Java

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

In der Methode onAnimationUpdate() können Sie auf den aktualisierten Animationswert zugreifen und ihn in einem Attribut einer Ihrer Ansichten verwenden. Weitere Informationen zu Listenern finden Sie im Abschnitt Animationslistener.

Mit ObjectAnimator animieren

ObjectAnimator ist eine Unterklasse von ValueAnimator (siehe vorheriger Abschnitt) und kombiniert die Timing-Engine und die Wertberechnung von ValueAnimator mit der Möglichkeit, eine benannte Eigenschaft eines Zielobjekts zu animieren. Dadurch wird die Animation von Objekten erheblich vereinfacht, da Sie ValueAnimator.AnimatorUpdateListener nicht mehr implementieren müssen, weil die animierte Eigenschaft automatisch aktualisiert wird.

Die Instanziierung eines ObjectAnimator-Objekts ähnelt der eines ValueAnimator-Objekts. Sie geben jedoch auch das Objekt und den Namen der Eigenschaft des Objekts (als String) zusammen mit den Werten an, zwischen denen animiert werden soll:

Kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

Damit die Attribute von ObjectAnimator richtig aktualisiert werden, müssen Sie Folgendes tun:

  • Das Objektattribut, das Sie animieren, muss eine Setter-Funktion (im CamelCase-Format) in der Form set<PropertyName>() haben. Da die ObjectAnimator-Property die Property während der Animation automatisch aktualisiert, muss sie mit dieser Setter-Methode darauf zugreifen können. Wenn der Attributname beispielsweise foo ist, benötigen Sie eine setFoo()-Methode. Wenn diese Setter-Methode nicht vorhanden ist, haben Sie drei Möglichkeiten:
    • Fügen Sie die Setter-Methode der Klasse hinzu, wenn Sie die entsprechenden Rechte haben.
    • Verwenden Sie eine Wrapper-Klasse, die Sie ändern dürfen, und lassen Sie den Wert mit einer gültigen Setter-Methode von dieser Wrapper-Klasse empfangen und an das ursprüngliche Objekt weiterleiten.
    • Verwenden Sie stattdessen „ValueAnimator“.
  • Wenn Sie in einer der ObjectAnimator-Factory-Methoden nur einen Wert für den Parameter values... angeben, wird davon ausgegangen, dass es sich um den Endwert der Animation handelt. Daher muss die Objekt-Property, die Sie animieren, eine Getter-Funktion haben, mit der der Startwert der Animation abgerufen wird. Die Getter-Funktion muss das Format get<PropertyName>() haben. Wenn der Attributname beispielsweise foo ist, benötigen Sie eine getFoo()-Methode.
  • Die Getter- (falls erforderlich) und Setter-Methoden der animierten Eigenschaft müssen denselben Typ wie die Start- und Endwerte haben, die Sie für ObjectAnimator angeben. Wenn Sie beispielsweise die folgende ObjectAnimator erstellen, müssen Sie targetObject.setPropName(float) und targetObject.getPropName() haben:
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • Je nachdem, welche Property oder welches Objekt Sie animieren, müssen Sie möglicherweise die Methode invalidate() für eine View aufrufen, damit der Bildschirm mit den aktualisierten animierten Werten neu gezeichnet wird. Dies erfolgt im onAnimationUpdate()-Callback. Wenn Sie beispielsweise die Farbeigenschaft eines Drawable-Objekts animieren, wird der Bildschirm nur aktualisiert, wenn das Objekt neu gezeichnet wird. Alle Property-Setter für View, z. B. setAlpha() und setTranslationX(), machen die View ordnungsgemäß ungültig. Sie müssen die View also nicht ungültig machen, wenn Sie diese Methoden mit neuen Werten aufrufen. Weitere Informationen zu Listenern finden Sie im Abschnitt Animationslistener.

Mehrere Animationen mit einem AnimatorSet choreografieren

Häufig möchten Sie eine Animation abspielen, die davon abhängt, wann eine andere Animation beginnt oder endet. Im Android-System können Sie Animationen in einem AnimatorSet zusammenfassen, um festzulegen, ob Animationen gleichzeitig, nacheinander oder nach einer bestimmten Verzögerung gestartet werden sollen. Sie können auch AnimatorSet-Objekte ineinander verschachteln.

Das folgende Code-Snippet spielt die folgenden Animator-Objekte auf folgende Weise ab:

  1. Spielt bounceAnim ab.
  2. Spielt gleichzeitig squashAnim1, squashAnim2, stretchAnim1 und stretchAnim2 ab.
  3. Spielt bounceBackAnim ab.
  4. Spielt fadeAnim ab.

Kotlin

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

Java

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

Animations-Listener

Mit den unten beschriebenen Listenern können Sie wichtige Ereignisse während einer Animation erfassen.

  • Animator.AnimatorListener
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate(): Wird für jeden Frame der Animation aufgerufen. Sie können auf dieses Ereignis warten, um die berechneten Werte zu verwenden, die von ValueAnimator während einer Animation generiert werden. Wenn Sie den Wert verwenden möchten, fragen Sie das ValueAnimator-Objekt ab, das an das Ereignis übergeben wurde, um den aktuellen animierten Wert mit der Methode getAnimatedValue() abzurufen. Die Implementierung dieses Listeners ist erforderlich, wenn Sie ValueAnimator verwenden.

      Je nachdem, welche Property oder welches Objekt Sie animieren, müssen Sie möglicherweise invalidate() für eine View aufrufen, damit dieser Bereich des Bildschirms mit den neuen animierten Werten neu gezeichnet wird. Wenn Sie beispielsweise die Farbeigenschaft eines Drawable-Objekts animieren, werden nur dann Aktualisierungen auf dem Bildschirm vorgenommen, wenn das Objekt neu gezeichnet wird. Alle Property-Setter für View, z. B. setAlpha() und setTranslationX(), machen die View ordnungsgemäß ungültig. Sie müssen die View also nicht ungültig machen, wenn Sie diese Methoden mit neuen Werten aufrufen.

Sie können die Klasse AnimatorListenerAdapter erweitern, anstatt die Schnittstelle Animator.AnimatorListener zu implementieren, wenn Sie nicht alle Methoden der Schnittstelle Animator.AnimatorListener implementieren möchten. Die Klasse AnimatorListenerAdapter bietet leere Implementierungen der Methoden, die Sie überschreiben können.

Mit dem folgenden Code-Snippet wird beispielsweise ein AnimatorListenerAdapter nur für den onAnimationEnd()-Callback erstellt:

Kotlin

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}

Java

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

Layoutänderungen für ViewGroup-Objekte animieren

Das Attributanimationssystem bietet die Möglichkeit, Änderungen an ViewGroup-Objekten zu animieren und View-Objekte auf einfache Weise zu animieren.

Mit der Klasse LayoutTransition können Sie Layoutänderungen in einer ViewGroup animieren. Ansichten in einer ViewGroup können eine Ein- und Ausblendanimation durchlaufen, wenn Sie sie einer ViewGroup hinzufügen oder daraus entfernen oder wenn Sie die Methode setVisibility() einer View mit VISIBLE, INVISIBLE oder GONE aufrufen. Die verbleibenden Ansichten in der ViewGroup können auch in ihre neuen Positionen animiert werden, wenn Sie Ansichten hinzufügen oder entfernen. Sie können die folgenden Animationen in einem LayoutTransition-Objekt definieren, indem Sie setAnimator() aufrufen und ein Animator-Objekt mit einer der folgenden LayoutTransition-Konstanten übergeben:

  • APPEARING: Ein Flag, das die Animation angibt, die für Elemente ausgeführt wird, die im Container angezeigt werden.
  • CHANGE_APPEARING: Ein Flag, das die Animation angibt, die für Elemente ausgeführt wird, die sich aufgrund eines neuen Elements im Container ändern.
  • DISAPPEARING: Ein Flag, das die Animation angibt, die für Elemente ausgeführt wird, die aus dem Container verschwinden.
  • CHANGE_DISAPPEARING: Ein Flag, das die Animation angibt, die für Elemente ausgeführt wird, die sich ändern, weil ein Element aus dem Container verschwindet.

Sie können eigene benutzerdefinierte Animationen für diese vier Arten von Ereignissen definieren, um das Aussehen Ihrer Layoutübergänge anzupassen. Alternativ können Sie das Animationssystem auch anweisen, die Standardanimationen zu verwenden.

So legen Sie das Attribut android:animateLayoutchanges für die ViewGroup auf true fest:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

Wenn Sie dieses Attribut auf „true“ setzen, werden automatisch Ansichten animiert, die der ViewGroup hinzugefügt oder daraus entfernt werden, sowie die verbleibenden Ansichten in der ViewGroup.

Änderungen des Ansichtsstatus mit StateListAnimator animieren

Mit der Klasse StateListAnimator können Sie Animators definieren, die ausgeführt werden, wenn sich der Status einer Ansicht ändert. Dieses Objekt fungiert als Wrapper für ein Animator-Objekt und ruft diese Animation auf, wenn sich der angegebene Ansichtsstatus (z. B. „pressed“ oder „focused“) ändert.

Der StateListAnimator kann in einer XML-Ressource mit einem <selector>-Stammelement und untergeordneten <item>-Elementen definiert werden, die jeweils einen anderen, durch die StateListAnimator-Klasse definierten Ansichtsstatus angeben. Jedes <item> enthält die Definition für eine Attributanimationsgruppe.

Mit der folgenden Datei wird beispielsweise ein Animator für die Statusliste erstellt, der die Skalierung der X- und Y-Achse der Ansicht ändert, wenn sie gedrückt wird:

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

Um den Animator für die Statusliste an eine Ansicht anzuhängen, fügen Sie das Attribut android:stateListAnimator wie folgt hinzu:

<Button android:stateListAnimator="@xml/animate_scale"
        ... />

Die in animate_scale.xml definierten Animationen werden jetzt verwendet, wenn sich der Status dieser Schaltfläche ändert.

Wenn Sie stattdessen einer Ansicht in Ihrem Code einen Animator für die Statusliste zuweisen möchten, verwenden Sie die Methode AnimatorInflater.loadStateListAnimator() und weisen Sie den Animator Ihrer Ansicht mit der Methode View.setStateListAnimator() zu.

Anstatt Eigenschaften der Ansicht zu animieren, können Sie mit AnimatedStateListDrawable eine Drawable-Animation zwischen Zustandsänderungen abspielen. Einige der System-Widgets in Android 5.0 verwenden diese Animationen standardmäßig. Im folgenden Beispiel sehen Sie, wie Sie AnimatedStateListDrawable als XML-Ressource definieren:

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

TypeEvaluator verwenden

Wenn Sie einen Typ animieren möchten, der dem Android-System unbekannt ist, können Sie einen eigenen Evaluator erstellen, indem Sie die TypeEvaluator-Schnittstelle implementieren. Die vom Android-System bekannten Typen sind int, float oder eine Farbe, die von den Typ-Evaluatoren IntEvaluator, FloatEvaluator und ArgbEvaluator unterstützt werden.

Im TypeEvaluator-Interface muss nur die evaluate()-Methode implementiert werden. So kann der verwendete Animator einen geeigneten Wert für die animierte Eigenschaft am aktuellen Punkt der Animation zurückgeben. Die Klasse FloatEvaluator zeigt, wie das geht:

Kotlin

private class FloatEvaluator : TypeEvaluator<Any> {

    override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any {
        return (startValue as Number).toFloat().let { startFloat ->
            startFloat + fraction * ((endValue as Number).toFloat() - startFloat)
        }
    }

}

Java

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

Hinweis:Wenn ValueAnimator (oder ObjectAnimator) ausgeführt wird, wird ein aktueller verstrichener Bruchteil der Animation (ein Wert zwischen 0 und 1) berechnet und dann eine interpolierte Version davon, je nachdem, welcher Interpolator verwendet wird. Der interpolierte Bruchteil wird über den Parameter fraction an TypeEvaluator übergeben. Sie müssen den Interpolator also nicht berücksichtigen, wenn Sie animierte Werte berechnen.

Interpolatoren verwenden

Ein Interpolator definiert, wie bestimmte Werte in einer Animation als Funktion der Zeit berechnet werden. Sie können beispielsweise festlegen, dass Animationen linear über die gesamte Animation hinweg erfolgen sollen. Das bedeutet, dass sich die Animation die ganze Zeit gleichmäßig bewegt. Sie können aber auch festlegen, dass Animationen nichtlineare Zeit verwenden sollen, z. B. durch Beschleunigung oder Verlangsamung am Anfang oder Ende der Animation.

Interpolator im Animationssystem erhalten einen Bruchteil von Animators, der die verstrichene Zeit der Animation darstellt. Interpolatoren ändern diesen Bruchteil, um ihn an den Animationstyp anzupassen, den sie bereitstellen sollen. Das Android-System bietet eine Reihe von gängigen Interpolatoren in der android.view.animation package. Wenn keine dieser Optionen Ihren Anforderungen entspricht, können Sie die TimeInterpolator-Schnittstelle implementieren und eine eigene erstellen.

Im Folgenden wird verglichen, wie der Standardinterpolator AccelerateDecelerateInterpolator und LinearInterpolator interpolierte Bruchteile berechnen. LinearInterpolator hat keine Auswirkungen auf den verstrichenen Bruchteil. Das AccelerateDecelerateInterpolator beschleunigt in die Animation hinein und verlangsamt sich wieder. Die Logik für diese Interpolatoren wird durch die folgenden Methoden definiert:

AccelerateDecelerateInterpolator

Kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

Java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

LinearInterpolator

Kotlin

override fun getInterpolation(input: Float): Float = input

Java

@Override
public float getInterpolation(float input) {
    return input;
}

In der folgenden Tabelle sind die ungefähren Werte dargestellt, die von diesen Interpolatoren für eine Animation mit einer Dauer von 1.000 ms berechnet werden:

ms elapsed Vergangener Bruchteil/Interpolierter Bruchteil (linear) Interpolierter Anteil (Beschleunigen/Verlangsamen)
0 0 0
200 0,2 ,1
400 ,4 0,345
600 .6 ,654
800 ,8 ,9
1000 1 1

Wie die Tabelle zeigt, ändert sich der LinearInterpolator mit der gleichen Geschwindigkeit, nämlich um 0,2 alle 200 ms. Mit AccelerateDecelerateInterpolator werden die Werte zwischen 200 ms und 600 ms schneller und zwischen 600 ms und 1.000 ms langsamer geändert als mit LinearInterpolator.

Keyframes festlegen

Ein Keyframe-Objekt besteht aus einem Zeit/Wert-Paar, mit dem Sie einen bestimmten Zustand zu einem bestimmten Zeitpunkt einer Animation definieren können. Jeder Keyframe kann auch einen eigenen Interpolator haben, um das Verhalten der Animation im Intervall zwischen der Zeit des vorherigen Keyframes und der Zeit dieses Keyframes zu steuern.

Wenn Sie ein Keyframe-Objekt instanziieren möchten, müssen Sie eine der Factory-Methoden ofInt(), ofFloat() oder ofObject() verwenden, um den entsprechenden Typ von Keyframe zu erhalten. Anschließend rufen Sie die Factory-Methode ofKeyframe() auf, um ein PropertyValuesHolder-Objekt zu erhalten. Sobald Sie das Objekt haben, können Sie einen Animator abrufen, indem Sie das PropertyValuesHolder-Objekt und das zu animierende Objekt übergeben. Das folgende Code-Snippet zeigt, wie das geht:

Kotlin

val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply {
    duration = 5000
}

Java

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000);

Ansichten animieren

Das System für die Eigenschaftenanimation ermöglicht eine optimierte Animation von View-Objekten und bietet einige Vorteile gegenüber dem System für die View-Animation. Das Animationssystem für Ansichten hat View-Objekte transformiert, indem die Art und Weise geändert wurde, wie sie gezeichnet wurden. Das wurde im Container der jeweiligen Ansicht gehandhabt, da die Ansicht selbst keine Eigenschaften hatte, die manipuliert werden konnten. Dadurch wurde die Ansicht animiert, aber das Ansichtsobjekt selbst wurde nicht geändert. Das führte zu einem Verhalten, bei dem ein Objekt weiterhin an seinem ursprünglichen Ort vorhanden war, obwohl es an einer anderen Stelle auf dem Bildschirm gezeichnet wurde. In Android 3.0 wurden neue Eigenschaften und die entsprechenden Getter- und Setter-Methoden hinzugefügt, um diesen Nachteil zu beseitigen.

Mit dem Property-Animationssystem können Sie Ansichten auf dem Bildschirm animieren, indem Sie die tatsächlichen Eigenschaften in den View-Objekten ändern. Außerdem wird in Ansichten automatisch die Methode invalidate() aufgerufen, um den Bildschirm zu aktualisieren, wenn sich seine Eigenschaften ändern. Die neuen Attribute in der Klasse View, die Attributanimationen ermöglichen, sind:

  • translationX und translationY: Mit diesen Eigenschaften wird festgelegt, wo sich die Ansicht relativ zu den Koordinaten für links und oben befindet, die vom Layoutcontainer festgelegt werden.
  • rotation, rotationX und rotationY: Mit diesen Attributen wird die Drehung in 2D (Attribut rotation) und 3D um den Drehpunkt gesteuert.
  • scaleX und scaleY: Mit diesen Eigenschaften wird die 2D-Skalierung einer View um ihren Drehpunkt gesteuert.
  • pivotX und pivotY: Mit diesen Eigenschaften wird die Position des Drehpunkts gesteuert, um den die Transformationsvorgänge für Drehung und Skalierung erfolgen. Standardmäßig befindet sich der Drehpunkt in der Mitte des Objekts.
  • x und y: Dies sind einfache Hilfseigenschaften, mit denen die endgültige Position der Ansicht in ihrem Container als Summe der Werte für „left“ und „top“ sowie „translationX“ und „translationY“ beschrieben wird.
  • 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).

Wenn Sie eine Eigenschaft eines View-Objekts animieren möchten, z. B. die Farbe oder den Rotationswert, müssen Sie nur einen Property-Animator erstellen und die View-Eigenschaft angeben, die animiert werden soll. Beispiel:

Kotlin

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)

Java

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

Weitere Informationen zum Erstellen von Animators finden Sie in den Abschnitten zum Animieren mit ValueAnimator und ObjectAnimator.

Mit ViewPropertyAnimator animieren

Mit ViewPropertyAnimator lassen sich mehrere Attribute eines View-Objekts parallel animieren. Dazu wird ein einzelnes zugrunde liegendes Animator-Objekt verwendet. Es verhält sich ähnlich wie ein ObjectAnimator, da es die tatsächlichen Werte der Eigenschaften der Ansicht ändert, ist aber effizienter, wenn viele Eigenschaften gleichzeitig animiert werden. Außerdem ist der Code für die Verwendung von ViewPropertyAnimator viel kürzer und leichter zu lesen. Die folgenden Code-Snippets zeigen die Unterschiede bei der Verwendung mehrerer ObjectAnimator-Objekte, eines einzelnen ObjectAnimator-Objekts und des ViewPropertyAnimator-Objekts, wenn die x- und y-Property einer Ansicht gleichzeitig animiert werden.

Mehrere ObjectAnimator-Objekte

Kotlin

val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
    playTogether(animX, animY)
    start()
}

Java

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

Ein ObjectAnimator

Kotlin

val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()

Java

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();

ViewPropertyAnimator

Kotlin

myView.animate().x(50f).y(100f)

Java

myView.animate().x(50f).y(100f);

Weitere Informationen zu ViewPropertyAnimator finden Sie im entsprechenden Blogpost für Android-Entwickler.

Animationen in XML deklarieren

Mit dem System für Property-Animationen können Sie Property-Animationen mit XML deklarieren, anstatt sie programmatisch zu erstellen. Wenn Sie Ihre Animationen in XML definieren, können Sie sie ganz einfach in mehreren Aktivitäten wiederverwenden und die Animationssequenz leichter bearbeiten.

Um Animationsdateien, die die neuen APIs für Eigenschaftsanimationen verwenden, von Dateien zu unterscheiden, die das alte Framework für Ansichtsanimationen verwenden, sollten Sie ab Android 3.1 die XML-Dateien für Eigenschaftsanimationen im Verzeichnis res/animator/ speichern.

Die folgenden Klassen für die Animation von Eigenschaften unterstützen die XML-Deklaration mit den folgenden XML-Tags:

Informationen zu den Attributen, die Sie in Ihrer XML-Deklaration verwenden können, finden Sie unter Animationsressourcen. Im folgenden Beispiel werden die beiden Gruppen von Objektanimationen nacheinander abgespielt. Die erste verschachtelte Gruppe enthält zwei Objektanimationen, die gleichzeitig abgespielt werden:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

Damit diese Animation ausgeführt werden kann, müssen Sie die XML-Ressourcen in Ihrem Code in ein AnimatorSet-Objekt einfügen und dann die Zielobjekte für alle Animationen festlegen, bevor Sie die Animationsgruppe starten. Durch den Aufruf von setTarget() wird ein einzelnes Zielobjekt für alle untergeordneten Elemente von AnimatorSet festgelegt. Der folgende Code zeigt, wie das geht:

Kotlin

(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply {
    setTarget(myObject)
    start()
}

Java

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

Sie können auch eine ValueAnimator in XML deklarieren, wie im folgenden Beispiel gezeigt:

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

Wenn Sie den vorherigen ValueAnimator in Ihrem Code verwenden möchten, müssen Sie das Objekt aufblähen, ein AnimatorUpdateListener hinzufügen, den aktualisierten Animationswert abrufen und ihn in einer Eigenschaft einer Ihrer Ansichten verwenden, wie im folgenden Code gezeigt:

Kotlin

(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }

    start()
}

Java

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

Informationen zur XML-Syntax zum Definieren von Attributanimationen finden Sie unter Animationsressourcen .

Mögliche Auswirkungen auf die UI-Leistung

Animatoren, die die Benutzeroberfläche aktualisieren, verursachen zusätzlichen Renderingaufwand für jeden Frame, in dem die Animation ausgeführt wird. Aus diesem Grund kann die Verwendung ressourcenintensiver Animationen die Leistung Ihrer App beeinträchtigen.

Die für die Animation der Benutzeroberfläche erforderliche Arbeit wird der Animationsphase der Rendering-Pipeline hinzugefügt. Sie können herausfinden, ob sich Ihre Animationen auf die Leistung Ihrer App auswirken, indem Sie Profil-GPU-Rendering aktivieren und die Animationsphase beobachten. Weitere Informationen finden Sie unter GPU-Rendering für Profil – Anleitung.