Das Property-Animationssystem ist ein robustes Framework, mit dem Sie fast alles animieren können. Sie können eine Animation definieren, um eine Objekteigenschaft im Zeitverlauf zu ändern, unabhängig davon, ob sie auf dem Bildschirm dargestellt wird oder nicht. Bei einer Eigenschaftsanimation wird der Wert einer Eigenschaft (ein Feld in einem Objekt) über einen bestimmten Zeitraum geändert. Zum Animieren geben Sie die Objekteigenschaft an, die Sie animieren möchten, z. B. seine Position auf dem Bildschirm, die Dauer der Animation und die Werte, zwischen denen animiert werden soll.
Mit dem Eigenschaftsanimationssystem können Sie die folgenden Eigenschaften einer Animation definieren:
- Dauer: Sie können die Dauer einer Animation festlegen. Die Standardlänge beträgt 300 ms.
- Zeitinterpolation: Sie können angeben, wie die Werte für die Eigenschaft als Funktion der aktuell verstrichenen Zeit der Animation berechnet werden.
- Wiederholungsanzahl und -verhalten: Sie können festlegen, ob eine Animation am Ende einer bestimmten Dauer wiederholt werden soll und wie oft die Animation wiederholt werden soll. Du kannst auch angeben, ob die Animation rückwärts abgespielt werden soll. Wenn Sie sie auf „Zurück“ einstellen, wird die Animation wiederholt vor und zurück wiedergegeben, bis die Anzahl der Wiederholungen erreicht ist.
- Animator-Sets: Sie können Animationen in logischen Sätzen gruppieren, die zusammen oder nacheinander oder nach einer bestimmten Verzögerung abgespielt werden.
- Verzögerung für Frame-Aktualisierung: Sie können angeben, wie oft die Frames Ihrer Animation aktualisiert werden sollen. Standardmäßig wird alle 10 ms eine Aktualisierung durchgeführt. Die Geschwindigkeit, mit der Ihre App Frames aktualisieren kann, hängt letztendlich davon ab, wie ausgelastet das System insgesamt ist und wie schnell das System den zugrunde liegenden Timer verarbeiten kann.
Ein vollständiges Beispiel für die Eigenschaftsanimation finden Sie in der Klasse ChangeColor
im Beispiel CustomTransition auf GitHub.
Funktionsweise der Property-Animation
Sehen wir uns zunächst anhand eines einfachen Beispiels an, wie eine Animation funktioniert. In Abbildung 1 ist ein hypothetisches Objekt zu sehen, das mithilfe der Eigenschaft x
animiert wird, die seine horizontale Position auf einem Bildschirm darstellt. Die Dauer der Animation ist auf 40 ms und die zurückzulegende Strecke 40 Pixel eingestellt. Alle 10 ms, was der Standard-Frame-Aktualisierungsrate entspricht, verschiebt sich das Objekt horizontal um 10 Pixel. Nach 40 ms endet die Animation und das Objekt endet an der horizontalen Position 40. Dies ist ein Beispiel für eine Animation mit linearer Interpolation, bei der sich das Objekt mit einer konstanten Geschwindigkeit bewegt.
Sie können auch Animationen mit einer nicht linearen Interpolation festlegen. In Abbildung 2 sehen Sie ein hypothetisches Objekt, das zu Beginn der Animation beschleunigt und am Ende der Animation langsamer wird. Das Objekt bewegt sich in 40 ms immer noch um 40 Pixel, aber nicht linear. Zu Beginn wird die Animation bis auf die Hälfte beschleunigt und wird dann von der Hälfte bis zum Ende der Animation verzögert. Wie Abbildung 2 zeigt, sind die zu Beginn und Ende der Animation zurückgelegten Strecken geringer als in der Mitte.
Sehen wir uns genau an, wie die wichtigen Komponenten des Property-Animationssystems Animationen wie die oben dargestellten berechnen würden. In Abbildung 3 ist dargestellt, wie die Hauptklassen miteinander funktionieren.
Das ValueAnimator
-Objekt erfasst das Timing der Animation, z. B. die Dauer der Animation und den aktuellen Wert der Eigenschaft, die animiert wird.
Der ValueAnimator
kapselt einen TimeInterpolator
, der die Animationsinterpolation definiert, und einen TypeEvaluator
, der definiert, wie Werte für die animierte Eigenschaft berechnet werden. In Abbildung 2 wird beispielsweise TimeInterpolator
AccelerateDecelerateInterpolator
und TypeEvaluator
IntEvaluator
verwendet.
Um eine Animation zu starten, erstellen Sie ein ValueAnimator
-Objekt und weisen ihm die Start- und Endwerte für die zu animierende Eigenschaft sowie die Dauer der Animation zu. Wenn Sie start()
aufrufen, beginnt die Animation. Während der gesamten Animation berechnet ValueAnimator
basierend auf der Dauer der Animation und der verstrichenen Zeit einen verstrichenen Anteil zwischen 0 und 1. Der Anteil der verstrichenen Zeit gibt an, wie lange die Animation bereits abgeschlossen ist. 0 bedeutet 0 % und 1 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 der ValueAnimator
einen verstrichenen Bruchteil berechnet hat, wird der aktuell festgelegte Anteil TimeInterpolator
aufgerufen, um einen interpolierten Bruchteil zu berechnen. Bei einem interpolierten Bruch wird der verstrichene Bruch einem neuen Anteil zugeordnet, der die festgelegte Zeitinterpolation berücksichtigt. Da die Animation beispielsweise langsam beschleunigt wird, ist der interpolierte Anteil von etwa 0,15 bei t = 10 ms kleiner als der verstrichene Anteil (0,25). In Abbildung 1 entspricht der interpolierte Anteil immer dem verstrichenen Anteil.
Wenn der interpolierte Bruch berechnet wird, ruft ValueAnimator
den entsprechenden TypeEvaluator
auf, um den Wert der Eigenschaft, die Sie animieren, anhand des interpolierten Bruchs, des Startwerts und des Endwerts der Animation zu berechnen. In Abbildung 2 betrug der interpolierte Bruch 0,15 bei t = 10 ms. Der Wert für die Eigenschaft zu diesem Zeitpunkt wäre also 0,15 × (40 - 0) oder 6.
Unterschied zwischen Property-Animation und Ansichtsanimation
Das Ansichtsanimationssystem bietet die Möglichkeit, nur View
-Objekte zu animieren. Wenn Sie also Nicht-View
-Objekte animieren möchten, müssen Sie dazu Ihren eigenen Code implementieren. Das Animationssystem für Ansichten ist außerdem dadurch eingeschränkt, dass es nur einige Aspekte eines zu animierenden View
-Objekts zur Verfügung stellt, z. B. die Skalierung und Drehung einer Ansicht, aber nicht die Hintergrundfarbe.
Ein weiterer Nachteil des Ansichtsanimationssystems besteht darin, dass es nur an der Stelle geändert wird, an der die Ansicht gezeichnet wurde, und nicht die tatsächliche Ansicht selbst. Wenn du beispielsweise eine Schaltfläche so animiert hast, dass sie sich über den Bildschirm bewegt, wird sie korrekt gezeichnet, aber die tatsächliche Stelle, an der du auf die Schaltfläche klicken kann, ändert sich nicht, sodass du deine eigene Logik implementieren musst, um dies zu handhaben.
Mit dem Eigenschaftsanimationssystem werden diese Einschränkungen vollständig entfernt. Sie können jede Eigenschaft eines beliebigen Objekts (Ansichten und Nicht-Ansichten) animieren, wobei das Objekt selbst tatsächlich geändert wird. Das Animationssystem für Properties ist außerdem robuster in der Art und Weise, wie Animationen ausgeführt werden. Auf übergeordneter Ebene weisen Sie den Eigenschaften, die Sie animieren möchten (z. B. Farbe, Position oder Größe), Animatoren zu. So können Sie Aspekte der Animation definieren, z. B. die Interpolation und Synchronisierung mehrerer Animatoren.
Das Ansichtsanimationssystem ist jedoch schneller eingerichtet und erfordert weniger Code zum Schreiben. Wenn die Ansichtsanimation alles erledigt, was Sie tun müssen, oder wenn Ihr vorhandener Code bereits wie gewünscht funktioniert, müssen Sie das Property-Animationssystem nicht verwenden. Außerdem kann es sinnvoll sein, beide Animationssysteme für verschiedene Situationen zu verwenden, wenn der Anwendungsfall eintritt.
API-Übersicht
Sie finden die meisten APIs des Property-Animationssystems unter android.animation
. Da das Ansichtsanimationssystem bereits viele Interpolatoren in android.view.animation
definiert, können Sie diese Interpolatoren auch im Eigenschaftsanimationssystem verwenden. In den folgenden Tabellen werden die Hauptkomponenten des Property-Animationssystems beschrieben.
Die Klasse Animator
bietet die Grundstruktur zum Erstellen von Animationen. Normalerweise verwenden Sie diese Klasse nicht direkt, da sie nur minimale Funktionalität bietet, die erweitert werden muss, um animierte Werte vollständig zu unterstützen. Die folgenden abgeleiteten Klassen erweitern Animator
:
Klasse | Beschreibung |
---|---|
ValueAnimator |
Die Haupt-Timing-Engine für die Eigenschaftsanimation, die auch die Werte für die zu animierende Eigenschaft berechnet. Sie umfasst alle Hauptfunktionen zum Berechnen von Animationswerten und enthält die Zeitdetails jeder Animation, Informationen darüber, ob sich eine Animation wiederholt, Listener, die Aktualisierungsereignisse empfangen, und die Möglichkeit, benutzerdefinierte Typen zur Auswertung festzulegen. Bei der Animation von Eigenschaften sind zwei Schritte erforderlich: Sie berechnen die animierten Werte und legen diese Werte für das Objekt und die Eigenschaft fest, die animiert werden. ValueAnimator übernimmt den zweiten Teil nicht. Daher müssen Sie auf Aktualisierungen von Werten warten, die von ValueAnimator berechnet wurden, und die Objekte, die Sie animieren möchten, mit Ihrer eigenen Logik ändern. Weitere Informationen finden Sie im Abschnitt zu Animationen mit ValueAnimator. |
ObjectAnimator |
Eine abgeleitete Klasse von ValueAnimator , mit der Sie ein Zielobjekt und eine Objekteigenschaft animieren können. Diese Klasse aktualisiert die Eigenschaft entsprechend, wenn sie einen neuen Wert für die Animation berechnet. In der Regel sollten Sie ObjectAnimator verwenden, da die Animation von Werten in Zielobjekten damit wesentlich einfacher wird. Gelegentlich möchten Sie ValueAnimator jedoch direkt verwenden, da für ObjectAnimator weitere Einschränkungen gelten. So müssen z. B. bestimmte Zugriffsmethoden auf dem Zielobjekt vorhanden sein. |
AnimatorSet |
Bietet einen Mechanismus zur Gruppierung von Animationen, sodass sie im Verhältnis zueinander ausgeführt werden. Sie können festlegen, dass Animationen zusammen, nacheinander oder nach einer bestimmten Verzögerung abgespielt werden sollen. Weitere Informationen finden Sie im Abschnitt Mehrere Animationen mit Animator-Sets choreografieren. |
Evaluatoren teilen dem Property-Animationssystem mit, wie die Werte für eine bestimmte Property berechnet werden sollen. Anhand der von einer Animator
-Klasse bereitgestellten Zeitdaten sowie des Start- und Endwerts der Animation werden die animierten Werte der Eigenschaft basierend auf diesen Daten berechnet. Das Animationssystem für Eigenschaften bietet die folgenden Bewerter:
Klasse/Benutzeroberfläche | Beschreibung |
---|---|
IntEvaluator |
Standard-Evaluator zum Berechnen von Werten für int -Properties. |
FloatEvaluator |
Standard-Evaluator zum Berechnen von Werten für float -Properties. |
ArgbEvaluator |
Standardauswerter zum Berechnen von Werten für Farbeigenschaften, die als Hexadezimalwerte dargestellt werden. |
TypeEvaluator |
Benutzeroberfläche, über die Sie Ihren eigenen Bewerter erstellen können Wenn Sie eine Objekteigenschaft animieren, die keine int -, float - oder Farbe ist, müssen Sie die TypeEvaluator -Schnittstelle implementieren, um anzugeben, wie die animierten Werte der Objekteigenschaft berechnet werden sollen. Sie können auch eine benutzerdefinierte 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 laufen, sodass sie sich gleichmäßig über die gesamte Zeit hinweg bewegt. Sie können auch Animationen festlegen, die eine nicht lineare Zeit verwenden, wie etwa die Beschleunigung am Anfang und die Verlangsamung am Ende der Animation. In Tabelle 3 werden die in android.view.animation
enthaltenen Interpolatoren beschrieben. Wenn keiner der verfügbaren Interpolatoren Ihren Anforderungen entspricht, implementieren Sie die TimeInterpolator
-Schnittstelle und erstellen Sie Ihre eigene. Weitere Informationen zum Schreiben eines benutzerdefinierten Interpolators finden Sie unter Interpolatoren verwenden.
Klasse/Benutzeroberfläche | Beschreibung |
---|---|
AccelerateDecelerateInterpolator |
Ein Interpolator, dessen Änderungsrate langsam beginnt und endet, aber durch die Mitte beschleunigt wird. |
AccelerateInterpolator |
Ein Interpolator, dessen Änderungsrate langsam beginnt und dann beschleunigt. |
AnticipateInterpolator |
Ein Interpolator, dessen Veränderung rückwärts beginnt und dann vorwärts schleudert. |
AnticipateOvershootInterpolator |
Ein Interpolator, dessen Änderung rückwärts beginnt, vorwärts springt, den Zielwert überschreitet und schließlich zum Endwert zurückkehrt. |
BounceInterpolator |
Ein Interpolator, dessen Änderung am Ende zurückspringt. |
CycleInterpolator |
Interpolator, dessen Animation sich für eine bestimmte Anzahl von Zyklen wiederholt. |
DecelerateInterpolator |
Ein Interpolator, dessen Änderungsrate schnell beginnt und dann langsamer wird. |
LinearInterpolator |
Interpolator, dessen Änderungsrate konstant ist. |
OvershootInterpolator |
Ein Interpolator, dessen Änderung vorwärts schleudert und den letzten Wert überschreitet, dann kommt zurück. |
TimeInterpolator |
Eine Schnittstelle, mit der Sie Ihren eigenen Interpolator implementieren können. |
Mit ValueAnimator Animationen erstellen
Mit der Klasse ValueAnimator
können Sie Werte eines beliebigen Typs für die Dauer einer Animation animieren. Dazu geben Sie eine Reihe von int
-, float
- oder Farbwerten an, die animiert werden sollen. Um eine ValueAnimator
zu erhalten, rufen Sie eine ihrer Factory-Methoden auf: 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 ValueAnimator
mit der Berechnung der Werte der Animation zwischen 0 und 100 für eine Dauer von 1.000 ms, wenn die Methode start()
ausgeführt wird.
Sie können auch einen benutzerdefinierten zu animierenden Typ angeben. Gehen Sie dazu so vor:
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
unter Verwendung der von MyTypeEvaluator
bereitgestellten Logik für eine Dauer von 1.000 ms, 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 einer Eigenschaft einer Ihrer Ansichten verwenden. Weitere Informationen zu Listenern finden Sie im Abschnitt zu Animations-Listenern.
Mit ObjectAnimator Animationen erstellen
ObjectAnimator
ist eine abgeleitete Klasse von ValueAnimator
(im vorherigen Abschnitt erläutert) und kombiniert die Timing-Engine und die Wertberechnung von ValueAnimator
mit der Möglichkeit, eine benannte Eigenschaft eines Zielobjekts zu animieren. Das macht das Animieren jedes Objekts viel einfacher, da Sie ValueAnimator.AnimatorUpdateListener
nicht mehr implementieren müssen, da die animierte Eigenschaft automatisch aktualisiert wird.
Die Instanziierung eines ObjectAnimator
ist mit einem ValueAnimator
vergleichbar. Allerdings geben Sie auch das Objekt und den Namen seiner Eigenschaft (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 ObjectAnimator
-Aktualisierungsattribute korrekt sind, müssen Sie Folgendes tun:
- Die Objekteigenschaft, die Sie animieren, muss eine Setter-Funktion (im Camel-Case-Schreibweise) in der Form
set<PropertyName>()
haben. DaObjectAnimator
die Eigenschaft während der Animation automatisch aktualisiert, muss sie mit dieser Setter-Methode auf die Eigenschaft zugreifen können. Wenn der Attributname beispielsweisefoo
lautet, benötigen Sie die MethodesetFoo()
. Wenn diese Setter-Methode nicht vorhanden ist, haben Sie drei Möglichkeiten:- Fügen Sie der Klasse die Setter-Methode hinzu, wenn Sie über die entsprechenden Rechte verfügen.
- Verwenden Sie eine Wrapper-Klasse, zu deren Änderung Sie berechtigt sind, und lassen Sie diesen Wrapper den Wert mit einer gültigen Setter-Methode empfangen und leiten Sie ihn an das ursprüngliche Objekt weiter.
- Verwende stattdessen
ValueAnimator
.
- Wenn Sie nur einen Wert für den Parameter
values...
in einer derObjectAnimator
-Factory-Methoden angeben, wird davon ausgegangen, dass dies der Endwert der Animation ist. Daher muss die Objekteigenschaft, die Sie animieren, eine Getter-Funktion haben, mit der der Startwert der Animation abgerufen wird. Die Getter-Funktion muss das Formatget<PropertyName>()
haben. Lautet der Attributname beispielsweisefoo
, benötigen Sie die MethodegetFoo()
. - Die Getter- und Setter-Methoden der zu animierenden Eigenschaft müssen mit demselben Typ wie die Start- und Endwerte, die Sie für
ObjectAnimator
angeben, ausgeführt werden. Sie müssen beispielsweisetargetObject.setPropName(float)
undtargetObject.getPropName()
haben, wenn Sie den folgendenObjectAnimator
erstellen:ObjectAnimator.ofFloat(targetObject, "propName", 1f)
- Je nachdem, welche Eigenschaft oder welches Objekt Sie animieren, müssen Sie möglicherweise die
invalidate()
-Methode für eine Ansicht aufrufen, damit der Bildschirm sich mit den aktualisierten animierten Werten neu zeichnen muss. Dies kannst du imonAnimationUpdate()
-Callback tun. Wenn du beispielsweise die Farbeigenschaft eines Drawable-Objekts animiert, werden nur dann Aktualisierungen am Bildschirm vorgenommen, wenn das Objekt neu gezeichnet wird. Alle Property-Setter für „View“, z. B.setAlpha()
undsetTranslationX()
, entwerten die Ansicht ordnungsgemäß. Sie müssen die Ansicht also nicht entwerten, wenn Sie diese Methoden mit neuen Werten aufrufen. Weitere Informationen zu Listenern finden Sie im Abschnitt zu Animations-Listenern.
Mehrere Animationen mit einem AnimatorSet choreografieren
In vielen Fällen möchten Sie eine Animation abspielen, die davon abhängt, wann eine andere Animation gestartet oder beendet wird. Mit dem Android-System können Sie Animationen in einer AnimatorSet
bündeln und so angeben, ob Animationen gleichzeitig, nacheinander oder nach einer bestimmten Verzögerung gestartet werden sollen. Sie können AnimatorSet
-Objekte auch ineinander verschachteln.
Im folgenden Code-Snippet werden die folgenden Animator
-Objekte so wiedergegeben:
- Spielt „
bounceAnim
“ ab. squashAnim1
,squashAnim2
,stretchAnim1
undstretchAnim2
werden gleichzeitig abgespielt.- Spielt „
bounceBackAnim
“ ab. - 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 während der Dauer einer Animation auf wichtige Ereignisse warten.
Animator.AnimatorListener
onAnimationStart()
– Wird beim Start der Animation aufgerufen.onAnimationEnd()
: Wird nach dem Ende der Animation aufgerufen.onAnimationRepeat()
– Wird aufgerufen, wenn sich die Animation wiederholt.onAnimationCancel()
: Wird beim Abbrechen der Animation aufgerufen. Bei einer abgebrochenen Animation wird auchonAnimationEnd()
aufgerufen, unabhängig davon, wie sie beendet wurden.
ValueAnimator.AnimatorUpdateListener
-
onAnimationUpdate()
– wird für jeden Frame der Animation aufgerufen. Warten Sie auf dieses Ereignis, um die berechneten Werte zu verwenden, die vonValueAnimator
während einer Animation generiert wurden. Wenn Sie den Wert verwenden möchten, fragen Sie das an das Ereignis übergebeneValueAnimator
-Objekt ab, um den aktuellen animierten Wert mit der MethodegetAnimatedValue()
zu erhalten. Die Implementierung dieses Listeners ist erforderlich, wenn SieValueAnimator
verwenden.Je nachdem, welche Eigenschaft oder welches Objekt Sie animieren, müssen Sie möglicherweise
invalidate()
für eine Ansicht aufrufen, damit dieser Bereich des Bildschirms sich mit den neuen animierten Werten neu gezeichnet wird. Wenn du beispielsweise die Farbeigenschaft eines Drawable-Objekts animiert, wird der Bildschirm nur aktualisiert, wenn das Objekt neu gezeichnet wird. Alle Property-Setter für die Datenansicht, z. B.setAlpha()
undsetTranslationX()
, entwerten die Ansicht ordnungsgemäß. Sie müssen die Ansicht also nicht entwerten, wenn Sie diese Methoden mit neuen Werten aufrufen.
-
Wenn Sie nicht alle Methoden der Animator.AnimatorListener
-Schnittstelle implementieren möchten, können Sie die Klasse AnimatorListenerAdapter
erweitern, statt die Animator.AnimatorListener
-Schnittstelle zu implementieren. 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 Animationssystem für Eigenschaften ermöglicht eine Animation von Änderungen an ViewGroup-Objekten sowie eine einfache Möglichkeit, View-Objekte selbst zu animieren.
Layoutänderungen innerhalb einer ViewGroup können Sie mit der Klasse LayoutTransition
animieren. Ansichten in einer ViewGroup können eine Animation durchlaufen, die ein- oder ausgeblendet wird, wenn Sie sie einer ViewGroup hinzufügen oder daraus entfernen oder die Methode setVisibility()
einer Ansicht mit VISIBLE
, INVISIBLE
oder GONE
aufrufen. Auch die übrigen Ansichten in der Ansichtsgruppe können an ihren 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
: Dieses Flag gibt die Animation für Elemente an, die im Container angezeigt werden.CHANGE_APPEARING
: Dieses Flag gibt die Animation für Elemente an, die sich aufgrund eines neuen Elements im Container ändern.DISAPPEARING
: Dieses Flag gibt die Animation für Elemente an, die aus dem Container verschwinden.CHANGE_DISAPPEARING
: Dieses Flag gibt die Animation für Elemente an, die sich ändern, weil ein Element aus dem Container verschwindet.
Sie können Ihre eigenen benutzerdefinierten Animationen für diese vier Ereignistypen definieren, um das Erscheinungsbild Ihrer Layoutübergänge anzupassen, oder einfach das Animationssystem 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" />
Wird dieses Attribut auf „true“ gesetzt, werden automatisch Ansichten animiert, die der ViewGroup hinzugefügt oder daraus entfernt werden. Das Gleiche gilt für die restlichen Datenansichten in der ViewGroup.
Änderungen des Ansichtsstatus mit StateListAnimator animieren
Mit der Klasse StateListAnimator
können Sie Animatoren definieren, die ausgeführt werden, wenn sich der Status einer Ansicht ändert. Dieses Objekt verhält sich wie ein Wrapper für ein Animator
-Objekt und ruft diese Animation immer dann auf, wenn sich der angegebene Ansichtsstatus (z. B. „gedrückt“ oder „fokussiert“) ändert.
Die StateListAnimator
kann in einer XML-Ressource mit einem <selector>
-Stammelement und untergeordneten <item>
-Elementen definiert werden, die jeweils einen anderen Ansichtsstatus angeben, der von der StateListAnimator
-Klasse definiert wird. Jedes <item>
enthält die Definition für ein Attribut-Animationsset.
Die folgende Datei erstellt beispielsweise einen Animator für Statuslisten, der beim Drücken die X- und Y-Skalierung der Ansicht ändert:
<?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
so hinzu:
<Button android:stateListAnimator="@xml/animate_scale" ... />
Jetzt werden die in animate_scale.xml
definierten Animationen verwendet, wenn sich der Status dieser Schaltfläche ändert.
Wenn Sie stattdessen einer Ansicht in Ihrem Code einen Animator für Statuslisten zuweisen möchten, verwenden Sie die Methode AnimatorInflater.loadStateListAnimator()
und weisen Sie den Animator Ihrer Ansicht mit der Methode View.setStateListAnimator()
zu.
Anstatt die Eigenschaften der Ansicht zu animieren, kannst du auch mit AnimatedStateListDrawable
eine Drawable-Animation zwischen Statusänderungen abspielen.
Einige System-Widgets in Android 5.0 verwenden diese Animationen standardmäßig. Das folgende Beispiel zeigt, wie ein AnimatedStateListDrawable
als XML-Ressource definiert wird:
<!-- 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 nicht bekannt ist, können Sie einen eigenen Evaluator erstellen, indem Sie die TypeEvaluator
-Schnittstelle implementieren. Dem Android-System sind die Typen int
, float
oder eine Farbe bekannt, die von den Typauswertern IntEvaluator
, FloatEvaluator
und ArgbEvaluator
unterstützt werden.
In der TypeEvaluator
-Schnittstelle kann nur eine Methode implementiert werden: die evaluate()
-Methode. So kann der Animator, den Sie verwenden, am aktuellen Zeitpunkt der Animation einen geeigneten Wert für Ihre animierte Eigenschaft zurückgeben. Die Klasse FloatEvaluator
veranschaulicht dies:
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 aktuell verstrichener Teil der Animation (ein Wert zwischen 0 und 1) berechnet und dann je nach verwendetem Interpolator eine interpolierte Version berechnet. Der interpolierte Anteil ist das, was die TypeEvaluator
über den Parameter fraction
erhält, sodass Sie den Interpolator bei der Berechnung animierter Werte nicht berücksichtigen müssen.
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 laufen, sodass sie sich gleichmäßig über die gesamte Zeit hinweg bewegt. Sie können auch Animationen festlegen, die eine nicht lineare Zeit verwenden, z. B. durch Beschleunigung oder Verlangsamung am Anfang oder Ende der Animation.
Interpolatoren im Animationssystem erhalten einen Anteil von Animators, der die verstrichene Zeit der Animation darstellt. Interpolatoren ändern diesen Anteil so, dass er mit der Art der Animation übereinstimmt, die bereitgestellt werden soll. Das Android-System bietet eine Reihe gängiger Interpolatoren im android.view.animation package
. Wenn keine dieser Optionen Ihren Anforderungen entspricht, können Sie die TimeInterpolator
-Schnittstelle implementieren und eine eigene erstellen.
Unten sehen Sie ein Beispiel dafür, wie der Standardinterpolator AccelerateDecelerateInterpolator
und der LinearInterpolator
interpolierte Brüche berechnen.
LinearInterpolator
hat keine Auswirkungen auf den verstrichenen Anteil. Der AccelerateDecelerateInterpolator
beschleunigt die Animation und wird aus ihr herausgezoomt. Die folgenden Methoden definieren die Logik für diese Interpolatoren:
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; }
Die folgende Tabelle enthält die ungefähren Werte, die von diesen Interpolatoren für eine 1.000 ms dauernde Animation berechnet werden:
ms verstrichen | Verstrichener Anteil/interpolierter Bruch (linear) | Interpolierter Bruch (beschleunigen/verzögern) |
---|---|---|
0 | 0 | 0 |
200 | 0,2 | 0,1 |
400 | 0,4 | 0,345 |
600 | 0,6 | 0,8 |
800 | 0,8 | 0,9 |
1.000 | 1 | 1 |
Wie die Tabelle zeigt, ändert LinearInterpolator
die Werte mit derselben Geschwindigkeit, nämlich 0,2 pro 200 ms. AccelerateDecelerateInterpolator
ändert die Werte schneller als LinearInterpolator
zwischen 200 ms und 600 ms und langsamer zwischen 600 und 1.000 ms.
Keyframes angeben
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 dem Zeitpunkt dieses Keyframes zu steuern.
Zum Instanziieren eines Keyframe
-Objekts müssen Sie eine der Factory-Methoden ofInt()
, ofFloat()
oder ofObject()
verwenden, um den entsprechenden Keyframe
-Typ zu erhalten. Anschließend rufen Sie die Factory-Methode ofKeyframe()
auf, um ein PropertyValuesHolder
-Objekt zu erhalten. Wenn Sie das Objekt haben, können Sie einen Animator abrufen. Übergeben Sie dazu das PropertyValuesHolder
-Objekt und das zu animierende Objekt. Das folgende Code-Snippet zeigt, wie dies funktioniert:
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);
Aufrufe animieren
Das Property-Animationssystem ermöglicht eine optimierte Animation von View-Objekten und bietet einige Vorteile gegenüber dem Ansichtsanimationssystem. Das Ansichtsanimationssystem transformierte View-Objekte, indem es die Art und Weise änderte, in der sie gezeichnet wurden. Diese Änderung wurde im Container jeder Ansicht vorgenommen, da die Ansicht selbst keine Eigenschaften hatte, die bearbeitet werden konnten. Dies führte dazu, dass die Ansicht animiert wurde, aber keine Änderung im View-Objekt selbst verursachte. Dies führte zu einem Verhalten, bei dem ein Objekt weiterhin an seiner ursprünglichen Position 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.
Das Eigenschaftsanimationssystem kann Ansichten auf dem Bildschirm animieren, indem die eigentlichen Eigenschaften in den View-Objekten geändert werden. Darüber hinaus wird in Views automatisch die Methode invalidate()
aufgerufen, um den Bildschirm zu aktualisieren, wenn sich seine Eigenschaften ändern. Dies sind die neuen Eigenschaften in der Klasse View
, die Eigenschaftsanimationen erstellen:
translationX
undtranslationY
: Mit diesen Eigenschaften wird festgelegt, wo sich die Ansicht als Delta zu den linken und oberen Koordinaten befindet, die durch den Layoutcontainer festgelegt werden.rotation
,rotationX
undrotationY
: Mit diesen Eigenschaften wird die 2D-Drehung (rotation
-Eigenschaft) und die 3D-Drehung um den Drehpunkt gesteuert.scaleX
undscaleY
: Mit diesen Eigenschaften wird die 2D-Skalierung einer Ansicht um ihren Drehpunkt festgelegt.pivotX
undpivotY
: Diese Eigenschaften steuern die Position des Drehpunkts, um den herum die Rotations- und Skalierungstransformationen erfolgen. Standardmäßig befindet sich der Drehpunkt im Zentrum des Objekts.x
undy
: Dies sind einfache Diensteigenschaften zur Beschreibung der endgültigen Position der Ansicht in ihrem Container, als Summe der Werte für den linken und oberen Rand und die Werte für die Übersetzung X und die Übersetzung Y.alpha
: Stellt die Alphatransparenz in der Ansicht dar. Der Standardwert ist 1 (undurchsichtig), wobei der Wert 0 für vollständige Transparenz (nicht sichtbar) steht.
Um eine Eigenschaft eines View-Objekts zu animieren, etwa seine Farbe oder den Rotationswert, müssen Sie lediglich einen Eigenschafts-Animator erstellen und die Ansichtseigenschaft 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 Animatoren finden Sie in den Abschnitten zur Animation mit ValueAnimator und ObjectAnimator.
Mit ViewPropertyAnimator Animationen erstellen
ViewPropertyAnimator
bietet eine einfache Möglichkeit, mehrere Attribute einer View
gleichzeitig zu animieren. Dazu wird ein einzelnes zugrunde liegendes Animator
-Objekt verwendet. Sie verhält sich ähnlich wie ObjectAnimator
, da sie die tatsächlichen Werte der Ansichtsattribute ändert, aber effizienter ist, wenn viele Attribute gleichzeitig animiert werden. Außerdem ist der Code zur Verwendung von ViewPropertyAnimator
viel prägnanter und leichter zu lesen. Die folgenden Code-Snippets zeigen die Unterschiede bei der Verwendung mehrerer ObjectAnimator
-Objekte, eines einzelnen ObjectAnimator
und der ViewPropertyAnimator
bei gleichzeitiger Animation der x
- und y
-Eigenschaften einer Ansicht.
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
findest du im entsprechenden Blogpost für Android-Entwickler.
Animationen in XML deklarieren
Mit dem Eigenschaftsanimationssystem können Sie Eigenschaftsanimationen mit XML deklarieren, anstatt dies programmatisch zu tun. Wenn Sie Ihre Animationen in XML definieren, können Sie sie einfach in mehreren Aktivitäten wiederverwenden und die Animationssequenz einfacher bearbeiten.
Damit Sie die Animationsdateien, die die neuen APIs für Eigenschaftsanimationen verwenden, von denen unterscheiden können, die das Legacy-Framework für Ansichtsanimationen ab Android 3.1 verwenden, sollten Sie die XML-Dateien für Eigenschaftsanimationen im Verzeichnis res/animator/
speichern.
Für die folgenden Eigenschaftsanimationsklassen wird die XML-Deklaration durch folgende XML-Tags unterstützt:
- „
ValueAnimator
“,<animator>
- „
ObjectAnimator
“,<objectAnimator>
- „
AnimatorSet
“,<set>
Informationen zu den Attributen, die Sie in Ihrer XML-Deklaration verwenden können, finden Sie unter Animationsressourcen. Im folgenden Beispiel werden die beiden Sätze von Objektanimationen nacheinander abgespielt, wobei im ersten verschachtelten Satz zwei Objektanimationen 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>
Um diese Animation auszuführen, müssen Sie die XML-Ressourcen in Ihrem Code auf ein AnimatorSet
-Objekt aufblähen und dann die Zielobjekte für alle Animationen festlegen, bevor Sie die Animation starten. Durch das Aufrufen von setTarget()
wird der Einfachheit halber ein einzelnes Zielobjekt für alle untergeordneten Elemente des AnimatorSet
-Elements festgelegt. Der folgende Code zeigt, wie das funktioniert:
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 ValueAnimator
auch 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 die vorherige ValueAnimator
in Ihrem Code verwenden möchten, müssen Sie das Objekt aufblasen, ein AnimatorUpdateListener
-Element hinzufügen, den aktualisierten Animationswert abrufen und ihn wie im folgenden Code in einer Eigenschaft einer Ihrer Ansichten verwenden:
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ätzliche Rendering-Arbeit für jeden Frame, in dem die Animation ausgeführt wird. Aus diesem Grund kann die Verwendung ressourcenintensiver Animationen die Leistung Ihrer App negativ beeinflussen.
Die zum Animieren der UI erforderlichen Schritte werden der Animationsphase der Rendering-Pipeline hinzugefügt. Sie können feststellen, ob sich Ihre Animationen auf die Leistung Ihrer App auswirken, indem Sie Profil-GPU-Rendering aktivieren und die Animationsphase überwachen. Weitere Informationen finden Sie unter Schritt-für-Schritt-Anleitung zum Profil-GPU-Rendering.