Il sistema di animazione delle proprietà è un solido framework che consente di animare quasi tutto. Puoi definire un'animazione per modificare qualsiasi proprietà dell'oggetto nel tempo, indipendentemente dal fatto che venga attirato sullo schermo o meno. L'animazione di una proprietà modifica il valore di una proprietà (un campo in un oggetto) entro un periodo di tempo specificato. Per animare un elemento, specifica la proprietà dell'oggetto che vuoi animare, ad esempio la posizione di un oggetto sullo schermo, la durata dell'animazione e i valori tra i quali vuoi animare.
Il sistema di animazione delle proprietà consente di definire le seguenti caratteristiche di un'animazione:
- Durata: puoi specificare la durata di un'animazione. La lunghezza predefinita è 300 ms.
- Interpolazione temporale: puoi specificare il modo in cui vengono calcolati i valori della proprietà come funzione del tempo trascorso attuale dell'animazione.
- Conteggio e comportamento ripetizioni: puoi specificare se un'animazione si ripete quando raggiunge la fine della durata e quante volte deve ripeterla. Puoi anche specificare se vuoi che l'animazione venga riprodotta al contrario. Impostando la modalità inversa, l'animazione viene riprodotta in avanti e indietro ripetutamente fino a raggiungere il numero di ripetizioni.
- Set di animazioni: puoi raggruppare le animazioni in set logici che vengono riprodotti insieme o in sequenza o dopo determinati ritardi.
- Ritardo aggiornamento frame: puoi specificare la frequenza di aggiornamento dei frame dell'animazione. L'impostazione predefinita è impostata per l'aggiornamento ogni 10 ms, ma la velocità con cui l'applicazione può aggiornare i frame dipende in ultima analisi dall'affollamento complessivo del sistema e dalla velocità con cui il sistema può gestire il timer sottostante.
Per un esempio completo di animazione della proprietà, vedi la classe ChangeColor
nell'esempio di CustomTransaction su GitHub.
Come funziona l'animazione della proprietà
Innanzitutto, vediamo come funziona un'animazione con un semplice esempio. La Figura 1 mostra un oggetto ipotetico animato con la sua proprietà x
, che rappresenta la sua posizione orizzontale su uno schermo. La durata dell'animazione è impostata su 40 ms e la distanza da percorrere è di 40 pixel. Ogni 10 ms, che è la frequenza di aggiornamento predefinita del frame, l'oggetto si sposta orizzontalmente di 10 pixel. Dopo 40 ms, l'animazione si interrompe e l'oggetto termina nella posizione orizzontale 40. Questo è un esempio di animazione con interpolazione lineare, vale a dire che l'oggetto si muove a una velocità costante.
![](https://developer.android.com/static/images/animation/animation-linear.png?authuser=19&hl=it)
Figura 1. Esempio di animazione lineare
Puoi anche specificare le animazioni in modo che abbiano un'interpolazione non lineare. La Figura 2 illustra un oggetto ipotetico che accelera all'inizio dell'animazione e rallenta alla fine dell'animazione. L'oggetto si sposta comunque di 40 pixel in 40 ms, ma in modo non lineare. All'inizio, questa animazione accelera fino al punto metà dell'animazione, poi rallenterà dal punto a metà fino alla fine dell'animazione. Come mostra la Figura 2, la distanza percorsa all'inizio e alla fine dell'animazione è inferiore a quella centrale.
![](https://developer.android.com/static/images/animation/animation-nonlinear.png?authuser=19&hl=it)
Figura 2. Esempio di animazione non lineare
Analizziamo nel dettaglio in che modo i componenti importanti del sistema di animazione della proprietà calcolano le animazioni come quelle illustrate sopra. La figura 3 mostra il funzionamento reciprocamente delle classi principali.
![](https://developer.android.com/static/images/animation/valueanimator.png?authuser=19&hl=it)
Figura 3. Come vengono calcolate le animazioni
L'oggetto ValueAnimator
tiene traccia dei tempi dell'animazione,
ad esempio la durata dell'animazione e il valore corrente della proprietà
che anima.
ValueAnimator
incapsula un TimeInterpolator
, che definisce l'interpolazione dell'animazione, e un TypeEvaluator
, che definisce le modalità di calcolo dei valori per la proprietà
animata. Ad esempio, nella Figura 2, il valore TimeInterpolator
utilizzato è AccelerateDecelerateInterpolator
e TypeEvaluator
è IntEvaluator
.
Per avviare un'animazione, crea un ValueAnimator
e assegnagli
i valori iniziale e finale per la proprietà da animare, insieme alla durata
dell'animazione. Quando chiami start()
, viene avviata l'animazione. Durante l'intera animazione, ValueAnimator
calcola una frazione trascorsa
compresa tra 0 e 1, in base alla durata dell'animazione e al tempo trascorso. La frazione trascorsa rappresenta la percentuale di tempo di completamento dell'animazione. 0 indica 0% e 1 indica il 100%. Ad esempio, nella Figura 1, la frazione trascorsa in t = 10 ms sarebbe 0,25
perché la durata totale è t = 40 ms.
Quando ValueAnimator
ha terminato di calcolare una frazione trascorsa,
chiama il valore TimeInterpolator
attualmente impostato per calcolare una
frazione interpolata. Una frazione interpolata mappa la frazione trascorsa a una nuova frazione che tiene conto dell'interpolazione temporale impostata. Ad esempio, nella Figura 2, perché l'animazione accelera lentamente, la frazione interpolata, circa 0,15, è inferiore alla frazione trascorso, ovvero 0,25, con t = 10 ms. Nella Figura 1, la frazione interpolata è sempre uguale alla frazione trascorsa.
Quando viene calcolata la frazione interpolata, ValueAnimator
chiama
il valore TypeEvaluator
appropriato, per calcolare il valore della
proprietà che stai animando, in base alla frazione interpolata, al valore iniziale e al
valore finale dell'animazione. Ad esempio, nella Figura 2, la frazione interpolata era 0,15 at t =
10 ms, quindi il valore per la proprietà in quel momento sarebbe 0,15 × (40 - 0) o 6.
Differenza tra l'animazione della proprietà e l'animazione della vista
Il sistema di animazione delle viste consente di animare solo oggetti View
, quindi per animare oggetti non View
è necessario implementare codice personalizzato. Il sistema di animazione della visualizzazione è inoltre vincolato dal fatto che espone solo alcuni aspetti di un oggetto View
da animare, come il ridimensionamento e la rotazione di una vista, ma non il colore di sfondo.
Un altro svantaggio del sistema di animazione delle viste è che ha modificato solo il punto in cui era disegnata la vista, non la vista effettiva. Ad esempio, se hai animato un pulsante in modo che si sposti sullo schermo, il pulsante viene tracciato correttamente, ma la posizione effettiva in cui puoi fare clic non cambia, quindi devi implementare una logica per gestire questa situazione.
Con il sistema di animazione delle proprietà, questi vincoli vengono completamente rimossi e puoi animare qualsiasi proprietà di qualsiasi oggetto (View e non View) determinando la modifica dell'oggetto stesso. Il sistema di animazione della proprietà è inoltre più efficace nella realizzazione dell'animazione. A livello generale, assegna animatori alle proprietà che vuoi animare, come colore, posizione o dimensione, e puoi definire aspetti dell'animazione come l'interpolazione e la sincronizzazione di più animatori.
Il sistema di animazione della visualizzazione, tuttavia, richiede meno tempo per la configurazione e meno codice da scrivere. Se l'animazione di una vista ti permette di fare tutto ciò che devi fare o se il codice esistente funziona già come vuoi tu, non è necessario utilizzare il sistema di animazione delle proprietà. Potrebbe anche avere senso utilizzare entrambi i sistemi di animazione per situazioni diverse, qualora si presentasse il caso d'uso.
Panoramica dell'API
Puoi trovare la maggior parte delle API del sistema di animazione delle proprietà in android.animation
. Poiché il sistema di animazione delle viste definisce già molti interpolatori in android.view.animation
, puoi utilizzare questi interpolatori anche nel sistema di animazione delle proprietà. Le seguenti tabelle descrivono i componenti principali del sistema di animazione delle proprietà.
La classe Animator
fornisce la struttura di base per la creazione delle animazioni. Normalmente non puoi utilizzare direttamente questa classe in quanto fornisce solo funzionalità minime che devono essere estese per supportare completamente i valori di animazione. Le seguenti
sottoclassi estendono Animator
:
Tabella 1. Animatori
Classe | Descrizione |
---|---|
ValueAnimator |
Il motore di temporizzazione principale per l'animazione delle proprietà, che calcola anche i valori per la
proprietà da animare. Include tutte le funzionalità di base per calcolare i valori dell'animazione e contiene i dettagli sui tempi di ogni animazione, informazioni sulla ripetizione di un'animazione, listener che ricevono eventi di aggiornamento e la possibilità di impostare tipi personalizzati da valutare. L'animazione delle proprietà comprende due parti: il calcolo dei valori animati e l'impostazione di questi valori sull'oggetto e sulla proprietà animata. ValueAnimator non esegue la seconda parte, quindi devi esaminare gli aggiornamenti dei valori calcolati da ValueAnimator e modificare gli oggetti che vuoi animare con la tua logica. Per ulteriori informazioni, consulta la sezione relativa all'animazione con ValueAnimator. |
ObjectAnimator |
Una sottoclasse di ValueAnimator che consente di impostare un oggetto
e una proprietà dell'oggetto target da animare. Questa classe aggiorna la proprietà di conseguenza quando
calcola un nuovo valore per l'animazione. Vuoi utilizzare
ObjectAnimator la maggior parte delle volte,
perché rende molto più semplice il processo di animazione dei valori sugli oggetti di destinazione. Tuttavia, a volte potresti voler utilizzare direttamente ValueAnimator perché ObjectAnimator prevede alcune limitazioni aggiuntive, ad esempio la richiesta di metodi di accesso specifici nell'oggetto di destinazione. |
AnimatorSet |
Fornisce un meccanismo per raggruppare le animazioni in modo che vengano eseguite l'una rispetto all'altra. Puoi impostare le animazioni in modo che vengano riprodotte insieme, in sequenza o dopo un determinato ritardo. Per ulteriori informazioni, consulta la sezione sulla Coreografia di più animazioni con set di animazioni. |
I valutatori indicano al sistema di animazione delle proprietà come calcolare i valori per una determinata
proprietà. Prendono i dati di temporizzazione forniti da una classe Animator
, i valori di inizio e fine dell'animazione, e calcolano i valori animati della proprietà
in base a questi dati. Il sistema di animazione delle proprietà fornisce i seguenti valutatori:
Tabella 2. Valutatori
Classe/interfaccia | Descrizione |
---|---|
IntEvaluator |
Il valutatore predefinito per calcolare i valori per le proprietà int . |
FloatEvaluator |
Il valutatore predefinito per calcolare i valori per le proprietà float . |
ArgbEvaluator |
Lo strumento di valutazione predefinito per calcolare i valori per le proprietà del colore rappresentate come valori esadecimali. |
TypeEvaluator |
Un'interfaccia che ti consente di creare un tuo strumento di valutazione. Se stai animando una proprietà di oggetto che non è int , float o colore, devi implementare l'interfaccia TypeEvaluator per specificare come calcolare i valori animati della proprietà dell'oggetto. Puoi anche specificare un valore TypeEvaluator personalizzato per i valori di int , float e colore, se vuoi elaborare questi tipi in modo diverso rispetto al comportamento predefinito.
Consulta la sezione sull'utilizzo di un TypeEvaluator per ulteriori
informazioni su come scrivere un valutatore personalizzato. |
Un interpolatore temporale definisce il modo in cui i valori specifici di un'animazione vengono calcolati come funzione del tempo. Ad esempio, puoi specificare che le animazioni vengano visualizzate in modo lineare su tutta
l'animazione, ovvero che si sposti in modo uniforme per tutto il tempo, oppure puoi specificare animazioni
per utilizzare un tempo non lineare, ad esempio l'accelerazione all'inizio e la decelerazione alla fine dell'animazione. La tabella 3 descrive gli interpolatori contenuti in android.view.animation
. Se nessuno degli interpolatori forniti soddisfa le tue esigenze, implementa l'interfaccia TimeInterpolator
e creane uno personalizzato. Per ulteriori informazioni su come scrivere un interpolatore personalizzato, consulta la sezione Utilizzo degli interpolatori.
Tabella 3. Interpolatori
Classe/interfaccia | Descrizione |
---|---|
AccelerateDecelerateInterpolator |
Un interpolatore la cui frequenza di cambiamento inizia e termina lentamente, ma accelera attraverso il mezzo. |
AccelerateInterpolator |
Un interpolatore la cui frequenza di cambiamento inizia lentamente e poi accelera. |
AnticipateInterpolator |
Un interpolatore il cui cambiamento inizia indietro e si sposta in avanti. |
AnticipateOvershootInterpolator |
Un interpolatore la cui modifica inizia all'indietro, si sposta in avanti e supera il valore target, per poi tornare al valore finale. |
BounceInterpolator |
Un interpolatore la cui modifica rimbalza alla fine. |
CycleInterpolator |
Un interpolatore la cui animazione si ripete per un determinato numero di cicli. |
DecelerateInterpolator |
Un interpolatore la cui frequenza di modifica inizia rapidamente e poi rallenta. |
LinearInterpolator |
Un interpolatore il cui tasso di variazione è costante. |
OvershootInterpolator |
Un interpolatore la cui modifica si lancia in avanti e supera l'ultimo valore, poi torna indietro. |
TimeInterpolator |
Un'interfaccia che consente di implementare un interpolatore personalizzato. |
Creazione di animazioni con ValueAnimator
La classe ValueAnimator
ti consente di animare valori di qualche tipo per
la durata di un'animazione specificando un insieme di valori int
, float
o colore
attraverso i quali animare. Puoi ottenere un ValueAnimator
chiamando uno dei suoi metodi di fabbrica: ofInt()
, ofFloat()
o ofObject()
. Ecco alcuni esempi:
Kotlin
ValueAnimator.ofFloat(0f, 100f).apply { duration = 1000 start() }
Java
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f); animation.setDuration(1000); animation.start();
In questo codice, ValueAnimator
inizia a calcolare i valori dell'animazione, compresi tra 0 e 100, per una durata di 1000 ms, quando viene eseguito il metodo start()
.
Puoi anche specificare un tipo personalizzato da animare procedendo nel seguente modo:
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 questo codice, ValueAnimator
inizia a calcolare i valori dell'animazione, tra startPropertyValue
e endPropertyValue
, utilizzando la logica fornita da MyTypeEvaluator
per una durata di 1000 ms, quando viene eseguito il metodo start()
.
Puoi utilizzare i valori dell'animazione aggiungendo
AnimatorUpdateListener
all'oggetto ValueAnimator
, come mostrato nel
seguente codice:
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); } });
Nel metodo onAnimationUpdate()
puoi accedere al valore aggiornato dell'animazione e utilizzarlo in una proprietà di una delle tue viste. Per ulteriori informazioni sui listener, consulta la sezione sui
Listener di animazione.
Creazione di animazioni con ObjectAnimator
ObjectAnimator
è una sottoclasse di ValueAnimator
(esaminata nella sezione precedente) e combina il calcolo
del motore di tempo e del valore di ValueAnimator
con la possibilità di
animare una proprietà con nome di un oggetto target. In questo modo, l'animazione di qualsiasi oggetto è molto più semplice, in quanto non è più necessario implementare ValueAnimator.AnimatorUpdateListener
, poiché la proprietà animata si aggiorna automaticamente.
La creazione di un'istanza per un ObjectAnimator
è simile a un ValueAnimator
, ma puoi specificare anche l'oggetto e il nome della sua proprietà (come stringa) insieme ai valori da animare tra:
Kotlin
ObjectAnimator.ofFloat(textView, "translationX", 100f).apply { duration = 1000 start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f); animation.setDuration(1000); animation.start();
Per fare in modo che le proprietà di aggiornamento di ObjectAnimator
siano corrette, devi seguire questi passaggi:
- La proprietà dell'oggetto che stai animando deve avere una funzione setter (in caso di cammello) nel formato
set<PropertyName>()
. PoichéObjectAnimator
aggiorna automaticamente la proprietà durante l'animazione, deve essere in grado di accedere alla proprietà con questo metodo di impostazione. Ad esempio, se il nome della proprietà èfoo
, devi avere un metodosetFoo()
. Se questo metodo di impostazione non esiste, hai tre opzioni:- Se disponi dei diritti necessari, aggiungi alla classe il metodo di impostazione.
- Utilizza una classe wrapper che hai il diritto di modificare e che il wrapper riceva il valore con un metodo di setter valido e lo inoltri all'oggetto originale.
- Usa invece il criterio
ValueAnimator
.
- Se specifichi un solo valore per il parametro
values...
in uno dei metodi di fabbricaObjectAnimator
, si presume che sia il valore finale dell'animazione. Pertanto, la proprietà dell'oggetto che stai animando deve avere una funzione getter utilizzata per ottenere il valore iniziale dell'animazione. La funzione getter deve essere nel formatoget<PropertyName>()
. Ad esempio, se il nome della proprietà èfoo
, devi avere un metodogetFoo()
. - I metodi getter (se necessario) e setter della proprietà che stai animando devono operare sullo stesso tipo dei valori iniziale e finale specificati in
ObjectAnimator
. Ad esempio, devi averetargetObject.setPropName(float)
etargetObject.getPropName()
se crei il seguenteObjectAnimator
:ObjectAnimator.ofFloat(targetObject, "propName", 1f)
- A seconda della proprietà o dell'oggetto che stai animando, potresti dover chiamare il metodo
invalidate()
su una vista per forzare lo schermo a ridisegnarsi con i valori animati aggiornati. A tale scopo, utilizza il callbackonAnimationUpdate()
. Ad esempio, l'animazione della proprietà colore di un oggetto Drawable causa aggiornamenti allo schermo solo quando l'oggetto viene ridisegnato. Tutti i setter delle proprietà su View, comesetAlpha()
esetTranslationX()
, invalidano correttamente la vista, quindi non è necessario invalidare la vista quando chiami questi metodi con nuovi valori. Per ulteriori informazioni sui listener, consulta la sezione sui Listener di animazione.
Crea una coreografia di più animazioni con un AnimatorSet
In molti casi, desideri riprodurre un'animazione che dipende dall'inizio o dalla fine di un'altra animazione. Il sistema Android ti consente di raggruppare le animazioni in un AnimatorSet
, in modo da poter specificare se avviare le animazioni
simultaneamente, in sequenza o dopo un determinato ritardo. Puoi anche nidificare AnimatorSet
oggetti l'uno all'interno dell'altro.
Il seguente snippet di codice riproduce i seguenti oggetti Animator
nel seguente modo:
- Riproduce
bounceAnim
. - Riproduce
squashAnim1
,squashAnim2
,stretchAnim1
estretchAnim2
contemporaneamente. - Riproduce
bounceBackAnim
. - Riproduce
fadeAnim
.
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();
Listener di animazione
Puoi ascoltare gli eventi importanti durante la durata di un'animazione con i listener descritti di seguito.
Animator.AnimatorListener
onAnimationStart()
- Richiamato all'avvio dell'animazione.onAnimationEnd()
: viene chiamato al termine dell'animazione.onAnimationRepeat()
: viene chiamato quando l'animazione si ripete.onAnimationCancel()
: viene chiamato quando l'animazione viene annullata. Un'animazione annullata chiama ancheonAnimationEnd()
, indipendentemente da come è stata terminata.
ValueAnimator.AnimatorUpdateListener
-
onAnimationUpdate()
: viene richiamato in ogni frame dell'animazione. Ascolta questo evento per utilizzare i valori calcolati generati daValueAnimator
durante un'animazione. Per utilizzare il valore, esegui una query sull'oggettoValueAnimator
passato nell'evento per ottenere il valore animato attuale con il metodogetAnimatedValue()
. Se utilizziValueAnimator
, è necessario implementare questo listener.A seconda della proprietà o dell'oggetto che stai animando, potresti dover richiamare
invalidate()
su una vista per forzare l'area dello schermo a ridisegnarsi con i nuovi valori animati. Ad esempio, l'animazione della proprietà colore di un oggetto Drawable causa gli aggiornamenti dello schermo solo quando l'oggetto viene ridisegnato. Tutti i setter delle proprietà sulla vista, comesetAlpha()
esetTranslationX()
, invalidano correttamente la vista; di conseguenza, non è necessario invalidare la vista quando chiami questi metodi con nuovi valori.
-
Puoi estendere la classe AnimatorListenerAdapter
anziché
implementare l'interfaccia Animator.AnimatorListener
, se non vuoi
implementare tutti i metodi dell'interfaccia Animator.AnimatorListener
. La classe AnimatorListenerAdapter
fornisce implementazioni
vuote dei metodi che puoi scegliere di sostituire.
Ad esempio, il seguente snippet di codice crea un AnimatorListenerAdapter
solo per il callback onAnimationEnd()
:
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()); }
Anima le modifiche al layout degli oggetti ViewGroup
Il sistema di animazione delle proprietà consente di animare le modifiche agli oggetti ViewGroup e fornisce un modo semplice per animare gli oggetti View autonomamente.
Puoi animare le modifiche al layout all'interno di un ViewGroup con la
classe LayoutTransition
. Le visualizzazioni all'interno di un ViewGroup possono passare attraverso un'animazione che appare e scompare quando le aggiungi o le rimuovi da un ViewGroup o quando chiami il metodo setVisibility()
di una vista con VISIBLE
, INVISIBLE
o GONE
. Anche le viste rimanenti in ViewGroup possono
animarsi nelle nuove posizioni quando aggiungi o rimuovi le viste. Puoi definire
le seguenti animazioni in un oggetto LayoutTransition
chiamando setAnimator()
e passando un oggetto Animator
con una delle
seguenti costanti LayoutTransition
:
APPEARING
: un flag che indica l'animazione in esecuzione sugli elementi visualizzati nel contenitore.CHANGE_APPEARING
: un flag che indica l'animazione in esecuzione sugli elementi che vengono modificati a causa della visualizzazione di un nuovo elemento nel contenitore.DISAPPEARING
: un flag che indica l'animazione in esecuzione sugli elementi che stanno scomparendo dal contenitore.CHANGE_DISAPPEARING
: un flag che indica l'animazione in esecuzione sugli elementi che vengono modificati a causa della scomparsa di un elemento dal contenitore.
Puoi definire animazioni personalizzate per questi quattro tipi di eventi al fine di personalizzare l'aspetto delle transizioni di layout o semplicemente indicare al sistema di animazione di utilizzare le animazioni predefinite.
Per impostare l'attributo android:animateLayoutchanges
su true
per
ViewGroup:
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/verticalContainer" android:animateLayoutChanges="true" />
L'impostazione di questo attributo su true anima automaticamente le viste aggiunte o rimosse dal ViewGroup, nonché dalle viste rimanenti in ViewGroup.
Animazione delle modifiche dello stato di visualizzazione utilizzando StateListAnimator
Il corso StateListAnimator
ti consente di definire animatori che vengono eseguiti quando
lo stato di una vista cambia. Questo oggetto si comporta come un wrapper per un
oggetto Animator
, chiamando l'animazione ogni volta che lo stato di visualizzazione
specificato (ad esempio "premuto" o "attivata") cambia.
StateListAnimator
può essere definito in una risorsa XML con un elemento <selector>
principale ed elementi <item>
secondari, ognuno dei quali specifica
un diverso stato di visualizzazione definito dalla classe StateListAnimator
. Ogni <item>
contiene la definizione di un set di animazione della proprietà.
Ad esempio, il seguente file crea un animatore per l'elenco di stati che modifica la scala x e y della vista quando viene premuta:
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>
Per allegare l'animatore dell'elenco di stati a una vista, aggiungi l'attributo
android:stateListAnimator
come segue:
<Button android:stateListAnimator="@xml/animate_scale" ... />
Ora le animazioni definite in animate_scale.xml
vengono utilizzate quando lo stato di questo pulsante
cambia.
In alternativa, per assegnare un animatore dell'elenco di stati a una vista nel codice, utilizza il metodo AnimatorInflater.loadStateListAnimator()
e assegna l'animatore alla vista con il metodo View.setStateListAnimator()
.
In alternativa, invece di animare le proprietà della vista, puoi riprodurre un'animazione disegnabile tra le modifiche di stato utilizzando AnimatedStateListDrawable
.
Alcuni widget di sistema in Android
5.0 usano queste animazioni per impostazione predefinita. L'esempio seguente mostra come definire un AnimatedStateListDrawable
come risorsa XML:
<!-- 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>
Usa un TypeEvaluator
Se vuoi animare un tipo sconosciuto al sistema Android, puoi creare un tuo
strumento di valutazione implementando l'interfaccia TypeEvaluator
. I tipi noti dal sistema Android sono int
, float
o un colore, supportati dai valutatori dei tipi IntEvaluator
, FloatEvaluator
e ArgbEvaluator
.
Esiste un solo metodo da implementare nell'interfaccia TypeEvaluator
: il metodo evaluate()
. In questo modo, l'animatore che stai utilizzando può restituire un valore appropriato per la tua proprietà animata nel punto corrente dell'animazione. Il corso FloatEvaluator
mostra come fare:
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); } }
Nota: quando viene eseguito ValueAnimator
(o ObjectAnimator
), calcola una frazione attuale trascorsa dell'animazione (un valore compreso tra 0 e 1) e quindi ne calcola una versione interpolata in base
all'interpolatore utilizzato. La frazione interpolata è quella che TypeEvaluator
riceve tramite il parametro fraction
, quindi non è necessario prendere in considerazione l'interpolatore quando calcoli i valori animati.
Utilizzare gli interpolatori
Un interpolatore definisce in che modo valori specifici in un'animazione vengono calcolati come funzione del tempo. Ad esempio, puoi specificare che le animazioni vengano visualizzate in modo lineare su tutta l'animazione, ovvero che l'animazione si sposti in modo uniforme per tutto il tempo, oppure puoi specificare animazioni per utilizzare un tempo non lineare, ad esempio utilizzando l'accelerazione o la decelerazione all'inizio o alla fine dell'animazione.
Gli interpolatori nel sistema di animazione ricevono una frazione dagli animatori che rappresentano il
tempo trascorso dell'animazione. Gli interpolatori modificano questa frazione in modo che coincida con il tipo di animazione che mira a fornire. Il sistema Android fornisce un insieme di interpolatori comuni in android.view.animation package
. Se nessuna di queste soluzioni soddisfa le tue esigenze, puoi implementare l'interfaccia TimeInterpolator
e crearne una personalizzata.
Ad esempio, di seguito viene confrontato il modo in cui l'interpolatore predefinito AccelerateDecelerateInterpolator
e LinearInterpolator
calcolano le frazioni interpolate.
Il valore LinearInterpolator
non ha alcun effetto sulla frazione trascorsa. AccelerateDecelerateInterpolator
accelera nell'animazione e
ne rallenta l'esterno. I seguenti metodi definiscono la logica per questi interpolatori:
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; }
La seguente tabella rappresenta i valori approssimativi calcolati da questi interpolatori per un'animazione che dura 1000 ms:
ms trascorsi | Frazione raggiunta/Frazione interpolata (Lineare) | Frazione interpolata (accelerazione/decelerazione) |
---|---|---|
0 | 0 | 0 |
200 | 0,2 | 0,1 |
400 | 0,4 | 0,345 |
600 | 0,6 | 0,8 |
800 | 0,8 | 0,9 |
1000 | 1 | 1 |
Come mostra la tabella, LinearInterpolator
cambia i valori alla stessa velocità, pari a 0,2 ogni 200 ms superati. AccelerateDecelerateInterpolator
modifica i valori più velocemente di LinearInterpolator
tra 200 ms e 600 ms e più lentamente tra 600 ms e 1000 ms.
Specificare i fotogrammi chiave
Un oggetto Keyframe
è costituito da una coppia tempo/valore che consente di definire uno stato specifico in un momento specifico di un'animazione. Ogni fotogramma chiave può anche avere il proprio
interpolatore per controllare il comportamento dell'animazione nell'intervallo tra il tempo del
fotogramma chiave precedente e il tempo del fotogramma chiave.
Per creare un'istanza di un oggetto Keyframe
, devi utilizzare uno dei metodi di
fabbrica, ofInt()
, ofFloat()
o ofObject()
per ottenere il tipo appropriato di Keyframe
. Chiamerai quindi il metodo di fabbrica ofKeyframe()
per ottenere un oggetto PropertyValuesHolder
. Una volta creato l'oggetto, puoi ottenere un animatore passando l'oggetto PropertyValuesHolder
e l'oggetto da animare. Il seguente snippet di codice mostra come eseguire questa operazione:
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);
Anima le visualizzazioni
Il sistema di animazione delle proprietà consente un'animazione semplificata degli oggetti View e offre alcuni vantaggi rispetto al sistema di animazione delle proprietà. Il sistema di animazione della vista ha trasformato gli oggetti View modificando il modo in cui erano disegnati. Questa operazione veniva gestita nel contenitore di ogni vista, perché la vista stessa non aveva proprietà da manipolare. Di conseguenza, la visualizzazione è stata animata, ma non ha causato modifiche all'oggetto View stesso. Ciò ha portato a un comportamento come un oggetto ancora esistente nella sua posizione originale, anche se è stato disegnato in una posizione diversa sullo schermo. In Android 3.0, sono state aggiunte nuove proprietà e i corrispondenti metodi getter e setter per eliminare questo svantaggio.
Il sistema di animazione delle proprietà può animare le viste sullo schermo modificando le proprietà effettive negli oggetti View. Inoltre, le viste chiamano automaticamente anche il metodo invalidate()
per aggiornare la schermata ogni volta che le relative proprietà vengono modificate. Le nuove proprietà nella classe View
che facilitano le animazioni delle proprietà sono:
translationX
etranslationY
: queste proprietà controllano la posizione della vista sotto forma di delta rispetto alle coordinate di sinistra e in alto, impostate dal relativo contenitore di layout.rotation
,rotationX
erotationY
: queste proprietà controllano la rotazione in 2D (proprietàrotation
) e in 3D intorno al punto pivot.scaleX
escaleY
: queste proprietà controllano il ridimensionamento 2D di una vista intorno al relativo punto pivot.pivotX
epivotY
: queste proprietà controllano la posizione del punto pivot attorno al quale avvengono le trasformazioni di rotazione e scalabilità. Per impostazione predefinita, il punto pivot si trova al centro dell'oggetto.x
ey
: queste sono semplici proprietà di utilità per descrivere la posizione finale della vista nel relativo container, come somma dei valori sinistro e superiore e dei valori di translationX e translationY.alpha
: rappresenta la trasparenza alfa nella vista. Questo valore è 1 (opaco) per impostazione predefinita, con il valore 0 che rappresenta la trasparenza completa (non visibile).
Per animare una proprietà di un oggetto View, come il colore o il valore di rotazione, è sufficiente creare un animatore di proprietà e specificare la proprietà View da animare. Ecco alcuni esempi:
Kotlin
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
Java
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
Per ulteriori informazioni sulla creazione di animatori, consulta le sezioni sull'animazione con ValueAnimator e ObjectAnimator.
Creazione di animazioni con ViewPropertyAnimator
ViewPropertyAnimator
consente di animare facilmente diverse proprietà di un elemento View
in parallelo, utilizzando un singolo oggetto Animator
sottostante. Si comporta in modo molto simile a un ObjectAnimator
, perché modifica i valori effettivi delle proprietà della vista, ma è più efficiente se si animano molte proprietà contemporaneamente. Inoltre, il codice per l'utilizzo di ViewPropertyAnimator
è molto
più conciso e più facile da leggere. I seguenti snippet di codice mostrano le differenze nell'utilizzo di più oggetti ObjectAnimator
, un singolo ObjectAnimator
e ViewPropertyAnimator
quando si animano contemporaneamente le proprietà x
e y
di una vista.
Più oggetti ObjectAnimator
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();
Un 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);
Per informazioni più dettagliate su ViewPropertyAnimator
, consulta il post del blog per gli sviluppatori Android corrispondente.
Dichiara le animazioni in XML
Il sistema di animazione delle proprietà ti consente di dichiarare le animazioni delle proprietà tramite XML anziché in modo programmatico. Se definisci le animazioni in XML, puoi riutilizzarle facilmente in più attività e modificare più facilmente la sequenza di animazione.
Per distinguere i file di animazione che utilizzano le nuove API di animazione delle proprietà da quelli che utilizzano il framework legacy di animazione della vista, a partire da Android 3.1, devi salvare i file XML per le animazioni delle proprietà nella directory res/animator/
.
Le seguenti classi di animazione delle proprietà supportano la dichiarazione XML con i seguenti tag XML:
ValueAnimator
-<animator>
ObjectAnimator
-<objectAnimator>
AnimatorSet
-<set>
Per trovare gli attributi che puoi utilizzare nella dichiarazione XML, consulta Risorse dell'animazione. L'esempio seguente riproduce i due insiemi di animazioni di oggetti in sequenza, con il primo set nidificato che riproduce due animazioni di oggetti:
<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>
Per eseguire questa animazione, devi aumentare in modo artificioso le risorse XML del tuo codice impostandole su un oggetto AnimatorSet
, quindi impostare gli oggetti di destinazione per tutte le animazioni prima di iniziare il set di animazioni. La chiamata a setTarget()
consente di impostare un singolo oggetto di destinazione per tutti gli elementi secondari di AnimatorSet
per comodità. Il seguente codice mostra come fare:
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();
Puoi anche dichiarare un ValueAnimator
in XML, come
mostrato nell'esempio seguente:
<animator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:valueType="floatType" android:valueFrom="0f" android:valueTo="-100f" />
Per utilizzare l'oggetto ValueAnimator
precedente nel codice, devi
gonfiare l'oggetto, aggiungere un
AnimatorUpdateListener
,
ottenere il valore dell'animazione aggiornato e utilizzarlo in una proprietà di una delle viste,
come illustrato nel seguente codice:
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();
Per informazioni sulla sintassi XML per la definizione delle animazioni delle proprietà, consulta Risorse dell'animazione .
Potenziali effetti sulle prestazioni dell'interfaccia utente
Gli animatori che aggiornano l'interfaccia utente comportano un lavoro di rendering aggiuntivo per ogni frame in cui viene eseguita l'animazione. Per questo motivo, l'utilizzo di animazioni che consumano molte risorse può influire negativamente sulle prestazioni dell'app.
Il lavoro necessario per animare la UI viene aggiunto alla fase di animazione della pipeline di rendering. Puoi scoprire se le animazioni influiscono sulle prestazioni della tua app attivando il Rendering GPU del profilo e monitorando la fase dell'animazione. Per ulteriori informazioni, consulta la procedura dettagliata di rendering delle GPU del profilo.