Panoramica dell'animazione della proprietà

Prova la funzionalità Scrivi
Jetpack Compose è il toolkit per l'interfaccia utente consigliato per Android. Scopri come utilizzare le animazioni in Scrittura.

Il sistema di animazione delle proprietà è un framework solido che consente di animare quasi tutto. Puoi definire un'animazione per modificare qualsiasi proprietà dell'oggetto nel tempo, che attiri o meno lo schermo. Un'animazione di proprietà modifica il valore di una proprietà (un campo in un oggetto) in un periodo di tempo specificato. Per animare un elemento, specifica della proprietà dell'oggetto che vuoi animare, come la posizione di un oggetto sullo schermo, il tempo per cui vuoi eseguire l'animazione e i valori tra i quali eseguire l'animazione.

Il sistema di animazione delle proprietà ti consente di definire le seguenti caratteristiche di una animazione:

  • Durata: puoi specificare la durata di un'animazione. La durata predefinita è 300 ms.
  • Interpolazione temporale: puoi specificare come vengono calcolati i valori della proprietà come funzione del tempo trascorso attuale dell'animazione.
  • Conteggio e comportamento ripetizioni: puoi specificare se un'animazione deve ripetersi quando raggiunge la fine di una durata e quante volte ripetere l'animazione. Puoi anche specificare se vuoi che l'animazione venga riprodotta in senso inverso. Impostazione delle riproduzioni invertite l'animazione in avanti e poi 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. Il valore predefinito è impostato su aggiornamento ogni 10 ms, ma la velocità con cui l'applicazione può aggiornare i frame dipende in ultima analisi dall'utilizzo complessivo del sistema e dalla velocità con cui il sistema può gestire il timer sottostante.

Per vedere un esempio completo di animazione delle proprietà, consulta la classe ChangeColor nell'esempio CustomTransition 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 per viaggiare è di 40 pixel. Ogni 10 ms, ovvero la frequenza di aggiornamento predefinita dei frame, l'oggetto si sposta orizzontalmente di 10 pixel. Dopo 40 ms, l'animazione si interrompe e l'oggetto termina in posizione orizzontale 40. Questo è un esempio di animazione con interpolazione lineare, il che significa che l'oggetto si muove a velocità costante.

Figura 1. Esempio di animazione lineare

Puoi anche specificare le animazioni per avere un'interpolazione non lineare. La Figura 2 mostra un oggetto ipotetico che accelera all'inizio dell'animazione e decelera alla fine dell'animazione. L'oggetto si sposta comunque di 40 pixel in 40 ms, ma in modo non lineare. Nella all'inizio, l'animazione accelera fino a metà strada, poi rallenterà dalla a metà strada fino alla fine dell'animazione. Come mostrato nella Figura 2, la distanza percorsa all'inizio e alla fine dell'animazione è inferiore rispetto a quella percorsa al centro.

Figura 2. Esempio di animazione non lineare

Diamo un'occhiata dettagliata a come i componenti importanti del sistema di animazione delle proprietà calcolano animazioni come quelle illustrate sopra. La Figura 3 mostra il funzionamento delle classi principali tra di loro.

Figura 3. Come vengono calcolate le animazioni

L'oggetto ValueAnimator tiene traccia della temporizzazione dell'animazione, ad esempio del tempo di esecuzione dell'animazione e del valore corrente della proprietà che viene animata.

ValueAnimator incapsula un TimeInterpolator, che definisce l'interpolazione dell'animazione, e un TypeEvaluator, che definisce come calcolare i valori per la proprietà animata. Ad esempio, nella Figura 2, il TimeInterpolator utilizzato è AccelerateDecelerateInterpolator e il TypeEvaluator è IntEvaluator.

Per avviare un'animazione, crea un ValueAnimator e assegnagli il i valori iniziali e finali per la proprietà che vuoi animare, insieme alla durata l'animazione. Quando chiami start() l'animazione l'avvio delle operazioni. Durante l'intera animazione, ValueAnimator calcola una frazione di tempo trascorso tra 0 e 1, in base alla durata dell'animazione e al tempo trascorso. La frazione di tempo trascorsa rappresenta la percentuale di tempo in cui l'animazione è stata completata, 0 significa 0% e 1 significa 100%. Ad esempio, nella Figura 1, la frazione di tempo trascorsa a t = 10 ms è 0,25 perché la durata totale è t = 40 ms.

Quando ValueAnimator ha terminato di calcolare una frazione di tempo trascorso, chiama 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, poiché l'animazione accelera lentamente, la frazione interpolata, circa 0,15, è inferiore alla frazione trascorsa, 0,25, a t = 10 ms. Nella Figura 1, la frazione interpolata è sempre uguale alla frazione trascorsa.

Quando viene calcolata la frazione interpolata, ValueAnimator chiama TypeEvaluator appropriato per calcolare il valore della proprietà di cui 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 pari a 0,15 e t = 10 ms, quindi il valore della 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 visualizzazioni offre la possibilità di animare solo gli oggetti View, quindi se vuoi animare oggetti diversi da View, devi implementare il tuo codice. Il sistema di animazione delle visualizzazioni è limitato anche dal fatto che espone solo alcuni aspetti di un oggetto View da animare, ad esempio la scala e la rotazione di una visualizzazione, ma non il colore di sfondo.

Un altro svantaggio del sistema di animazione della visualizzazione è che modificava solo la posizione in cui veniva disegnata la visualizzazione e non la visualizzazione stessa. Ad esempio, se hai animato un pulsante in modo che si muova sullo schermo, il pulsante viene disegnato correttamente, ma la posizione effettiva in cui puoi fare clic sul pulsante non cambia, quindi devi implementare la tua logica per gestire questo problema.

Con il sistema di animazione delle proprietà, questi vincoli vengono rimossi completamente e puoi animare qualsiasi proprietà di qualsiasi oggetto (viste e non) e l'oggetto stesso viene effettivamente modificato. Il sistema di animazione delle proprietà è anche più solido nel modo in cui esegue l'animazione. Alle ore A livello generale, assegni animatori alle proprietà che vuoi animare, come colore, posizione o dimensione e può definire aspetti dell'animazione come l'interpolazione la sincronizzazione di più animatori.

Tuttavia, il sistema di animazione della visualizzazione richiede meno tempo per la configurazione e meno codice da scrivere. Se l'animazione di visualizzazione ti permette di fare tutto ciò che devi fare o se il codice esistente è già funziona nel modo che preferisci, senza bisogno di usare il sistema di animazione della proprietà. Potrebbe anche ha senso utilizzare entrambi i sistemi di animazione per situazioni diverse, qualora si presenti 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 visualizzazione delle animazioni definisce molti interpolatori in android.view.animation, puoi utilizzare per questi interpolatori anche nel sistema di animazione delle proprietà. Le tabelle seguenti descrivono i componenti principali del sistema di animazione delle proprietà.

La classe Animator fornisce la struttura di base per creare animazioni. In genere, non utilizzi questa classe direttamente perché fornisce solo funzionalità minime che devono essere estese per supportare completamente l'animazione dei valori. I 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 della proprietà da animare. Include tutte le funzionalità di base che calcolano l'animazione. e contiene i dettagli di temporizzazione di ciascuna animazione, informazioni sull'eventuale l'animazione si ripete, i listener che ricevono eventi di aggiornamento e la possibilità di impostare tipi da valutare. L'animazione delle proprietà è composta da due parti: il calcolo dell'animazione e l'impostazione di questi valori sull'oggetto e sulla proprietà che vengono animati. ValueAnimator non esegue il secondo pezzo, quindi devi ascoltare per gli aggiornamenti ai valori calcolati da ValueAnimator e modificare gli oggetti da animare con la tua logica. Per ulteriori informazioni, consulta la sezione su Animazione con ValueAnimator.
ObjectAnimator Una sottoclasse di ValueAnimator che consente di impostare un oggetto di destinazione e una proprietà dell'oggetto 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 target. Tuttavia, a volte potresti voler utilizzare direttamente ValueAnimator perché ObjectAnimator ha alcune limitazioni aggiuntive, ad esempio la richiesta di della funzione di accesso di Google Cloud nell'oggetto di destinazione.
AnimatorSet Offre un meccanismo per raggruppare le animazioni in modo che vengano eseguite relazione tra loro. Puoi impostare le animazioni in modo che vengano riprodotte insieme, in sequenza o dopo un ritardo specificato. Per ulteriori informazioni, consulta la sezione Coreografia di più animazioni con gli insiemi di animatori.

I valutatori indicano al sistema di animazione delle proprietà come calcolare i valori per un determinato proprietà. Prendono i dati sulle tempistiche forniti da un Animator , i valori di inizio e fine dell'animazione e calcolano i valori animati della proprietà sulla base di 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 Il valutatore predefinito per calcolare i valori per le proprietà di colore rappresentate come valori esadecimali.
TypeEvaluator Un'interfaccia che ti consente di creare un tuo strumento di valutazione. Se stai animando una proprietà oggetto che non è int, float o un colore, devi implementare l'interfaccia TypeEvaluator per specificare come calcolare i valori animati della proprietà oggetto. Puoi anche specificare un TypeEvaluator personalizzato per i valori int, float e colore se vuoi elaborare questi tipi in modo diverso rispetto al comportamento predefinito. Per ulteriori informazioni su come scrivere un valutatore personalizzato, consulta la sezione Utilizzo di un valutatore di tipo.

Un interpolatore temporale definisce in che modo vengono calcolati valori specifici in un'animazione come funzione del tempo. Ad esempio, puoi specificare che le animazioni si verifichino in modo lineare nell'intera animazione, ovvero che si muovano in modo uniforme per tutto il tempo, oppure puoi specificare che le animazioni utilizzino un tempo non lineare, ad esempio accelerando all'inizio e decelerando alla fine dell'animazione. La tabella 3 descrive gli interpolatori contenuti in android.view.animation. Se nessuno degli interpolatori forniti è adatto in base alle tue esigenze, implementa l'interfaccia TimeInterpolator e creane una personalizzata. Consulta la sezione Utilizzo degli interpolatori per ulteriori informazioni su come scrivere un prompt personalizzato dell'interpolatore.

Tabella 3. Interpolatori

Classe/interfaccia Descrizione
AccelerateDecelerateInterpolator Un interpolatore la cui frequenza di cambiamento inizia e termina lentamente ma accelera al centro.
AccelerateInterpolator Un interpolatore la cui velocità di variazione inizia lentamente e poi accelera.
AnticipateInterpolator Un interpolatore la cui variazione inizia all'indietro e poi si sposta in avanti.
AnticipateOvershootInterpolator Un interpolatore il cui cambiamento inizia all'indietro, si lancia in avanti e supera il valore target, per poi tornare al valore finale.
BounceInterpolator Un interpolatore la cui variazione rimbalza alla fine.
CycleInterpolator Un interpolatore la cui animazione si ripete per un determinato numero di cicli.
DecelerateInterpolator Un interpolatore il cui tasso di variazione inizia rapidamente e poi rallenta.
LinearInterpolator Un interpolatore il cui tasso di variazione è costante.
OvershootInterpolator Un interpolatore la cui modifica si sposta in avanti e supera l'ultimo valore, poi rientra.
TimeInterpolator Un'interfaccia che consente di implementare un interpolatore personalizzato.

Creare animazioni utilizzando ValueAnimator

La classe ValueAnimator consente di animare valori di un determinato tipo per la durata di un'animazione specificando un insieme di valori int, float o di colore da animare. Puoi ottenere un ValueAnimator chiamando uno dei suoi metodi di fabbrica: ofInt(), ofFloat() o ofObject(). Ad esempio:

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'attributo dell'animazione, tra startPropertyValue e endPropertyValue utilizzando logica fornita da MyTypeEvaluator per una durata di 1000 ms, quando viene eseguito il metodo start().

Puoi utilizzare i valori dell'animazione aggiungendo un parametro AnimatorUpdateListener all'oggetto ValueAnimator, come mostrato codice seguente:

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 onAnimationUpdate() puoi accedere al valore aggiornato dell'animazione e utilizzarlo in una proprietà una delle tue viste. Per ulteriori informazioni sugli ascoltatori, consulta la sezione su Ascoltatori di animazioni.

Creare animazioni utilizzando ObjectAnimator

ObjectAnimator è una sottoclasse di ValueAnimator (discussa nella sezione precedente) e combina il motore di temporizzazione e il calcolo del valore di ValueAnimator con la possibilità di animare una proprietà denominata di un oggetto target. In questo modo l'animazione di qualsiasi oggetto è molto più facile, non è più necessario implementare ValueAnimator.AnimatorUpdateListener, perché la proprietà animata si aggiorna automaticamente.

L'inizializzazione di un ObjectAnimator è simile a quella di un ValueAnimator, ma devi specificare anche l'oggetto e il nome della relativa proprietà (come stringa) insieme ai valori tra cui eseguire l'animazione:

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 ObjectAnimator aggiorni le proprietà devi effettuare le seguenti operazioni:

  • La proprietà dell'oggetto che stai animando deve avere una funzione di impostazione (in CamelCase) sotto forma di set<PropertyName>(). Poiché ObjectAnimator aggiorna automaticamente la proprietà durante l'animazione, deve potervi accedere con questo metodo del setter. Ad esempio, se il nome della proprietà è foo, devi hanno un metodo setFoo(). Se questo metodo di impostazione non esiste, hai tre opzioni:
    • Aggiungi il metodo setter alla classe se disponi dei diritti necessari.
    • Utilizza una classe wrapper di cui disponi dei diritti di modifica e che il wrapper riceva il con un metodo setter valido e inoltrarlo all'oggetto originale.
    • Usa invece il criterio ValueAnimator.
  • Se specifichi un solo valore per il parametro values... in uno dei metodi di fabbrica ObjectAnimator, si presume che sia il valore finale dell'animazione. Pertanto, la proprietà dell'oggetto che stai animando deve avere una funzione di getter utilizzata per ottenere il valore iniziale dell'animazione. La funzione di getter deve avere il formato get<PropertyName>(). Ad esempio, se il nome della proprietà è foo, devi avere un metodo getFoo().
  • I metodi getter (se necessario) e setter della proprietà che stai animando devono operare sullo stesso tipo dei valori iniziale e finale specificati per ObjectAnimator. Ad esempio, devi avere targetObject.setPropName(float) e targetObject.getPropName() se crei il seguente ObjectAnimator:
    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 il metodo valori animati aggiornati. Puoi farlo nel onAnimationUpdate() di Google. Ad esempio, l'animazione della proprietà color di un oggetto Drawable provoca aggiornamenti della schermata solo quando l'oggetto si ridisegna. Tutte le impostazioni di proprietà su View, ad esempio setAlpha() e setTranslationX() invalida correttamente la vista, quindi non è necessario invalidarla quando chiami questi con nuovi valori. Per ulteriori informazioni sugli ascoltatori, consulta la sezione relativa ai ascoltatori di animazione.

Crea una coreografia di più animazioni con un AnimatorSet

In molti casi, desideri riprodurre un'animazione che dipende dall'avvio o dall'avvio di un'altra animazione. finiture in cui sono finite. Il sistema Android ti consente di raggruppare le animazioni in un AnimatorSet, in modo da poter specificare se avviarle contemporaneamente, in sequenza o dopo un ritardo specificato. Puoi anche nidificare AnimatorSet oggetti l'uno all'interno dell'altro.

Il seguente snippet di codice riproduce il seguente Animator nel seguente modo:

  1. Riproduce bounceAnim.
  2. Riproduce squashAnim1, squashAnim2, stretchAnim1 e stretchAnim2 contemporaneamente.
  3. Riproduci bounceBackAnim.
  4. 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
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate(): viene richiamato in ogni frame dell'animazione. Ascolta questo evento per utilizzare i valori calcolati generati da ValueAnimator durante un animazione. Per utilizzare il valore, esegui una query sull'oggetto ValueAnimator passato all'evento per ottenere il valore animato corrente con il metodo getAnimatedValue(). In fase di implementazione il listener è obbligatorio se utilizzi ValueAnimator.

      A seconda della proprietà o dell'oggetto che stai animando, potrebbe essere necessario chiamare invalidate() su una vista per forzare quell'area dell'elemento per ridisegnarsi con i nuovi valori animati. Ad esempio, l'animazione della proprietà colore di un oggetto Drawable causa aggiornamenti sullo schermo solo quando l'oggetto si ridisegna. Tutti gli attributi di impostazione della visualizzazione, come setAlpha() e setTranslationX(), invalidano correttamente la visualizzazione, quindi non è necessario invalidarla quando chiami questi metodi con nuovi valori.

Se non vuoi implementare tutti i metodi dell'interfaccia Animator.AnimatorListener, puoi estendere la classe AnimatorListenerAdapter anziché implementare l'interfaccia Animator.AnimatorListener. La classe AnimatorListenerAdapter fornisce elementi le implementazioni dei metodi che puoi scegliere di sostituire.

Ad esempio, il seguente snippet di codice crea un AnimatorListenerAdapter solo per onAnimationEnd() callback:

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 nonché un modo semplice per animare gli oggetti View.

Puoi animare le modifiche al layout all'interno di un ViewGroup con il LayoutTransition corso. Le visualizzazioni all'interno di un ViewGroup possono essere visualizzate e nascoste tramite un'animazione quando le aggiungi o le rimuovi da un ViewGroup o quando chiami il metodo setVisibility() di una visualizzazione con VISIBLE, INVISIBLE o GONE. Le viste rimanenti di ViewGroup possono anche si anima nelle nuove posizioni quando aggiungi o rimuovi visualizzazioni. Puoi definire le seguenti animazioni in un oggetto LayoutTransition chiamando il numero setAnimator() e passando un oggetto Animator con uno dei le seguenti costanti LayoutTransition:

  • APPEARING: un flag che indica l'animazione che viene eseguita sugli elementi visualizzati nel contenitore.
  • CHANGE_APPEARING: un flag che indica l'animazione che viene eseguita sugli elementi in fase di modifica a causa della visualizzazione di un nuovo elemento nel contenitore.
  • DISAPPEARING: un flag che indica l'animazione eseguita sugli elementi che vengono scomparirà dal contenitore.
  • CHANGE_DISAPPEARING: un flag che indica l'animazione che viene eseguita sugli elementi che cambiano a causa della scomparsa di un elemento dal contenitore.

Puoi definire le tue animazioni personalizzate per questi quattro tipi di eventi per personalizzare l'aspetto delle transizioni del 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 visualizzazioni aggiunte o rimosse dal ViewGroup e le restanti viste in ViewGroup.

Animare le modifiche dello stato della visualizzazione utilizzando StateListAnimator

Il corso StateListAnimator ti consente di definire animatori da eseguire lo stato di una vista cambia. Questo oggetto si comporta come un wrapper per Animator, richiamando l'animazione ogni volta che viene specificato modifiche allo stato di visualizzazione (ad esempio "premuto" o "attivata").

StateListAnimator può essere definito in una risorsa XML con un L'elemento <selector> e gli elementi <item> secondari specificati ciascuno un altro stato di visualizzazione definito dalla classe StateListAnimator. Ciascuna <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 premuto:

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 android:stateListAnimator come segue:

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

Ora le animazioni definite in animate_scale.xml vengono utilizzate quando cambia lo stato di questo pulsante.

In alternativa, per assegnare un animatore dell'elenco di stati a una vista nel tuo codice, utilizza il metodo AnimatorInflater.loadStateListAnimator() e assegna l'animatore a la tua visualizzazione con il metodo View.setStateListAnimator().

In alternativa, anziché animare le proprietà della visualizzazione, puoi riprodurre un'animazione drawable tra le modifiche di stato utilizzando AnimatedStateListDrawable. Alcuni widget di sistema Android 5.0 utilizza 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 il tuo valutatore implementando l'interfaccia TypeEvaluator. I tipi conosciuti dal sistema Android sono int, float o un colore, supportati dagli valutatori di tipo IntEvaluator, FloatEvaluator e ArgbEvaluator.

Esiste un solo metodo da implementare nell'interfaccia TypeEvaluator , ovvero il metodo evaluate(). Ciò consente l'animatore che stai utilizzando per restituire un valore appropriato per la tua proprietà animata nel campo punto corrente dell'animazione. La classe FloatEvaluator mostra come eseguire questa operazione:

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), viene calcolata una frazione corrente dell'animazione trascorsa (un valore compreso tra 0 e 1) e poi una versione interpolata in base all'interpolatore utilizzato. La frazione interpolata è ciò che TypeEvaluator riceve tramite il parametro fraction, quindi non devi tenere conto dell'interpolatore durante il calcolo dei valori animati.

Utilizzare gli interpolatori

Un interpolatore definisce in che modo valori specifici in un'animazione vengono calcolati come funzione di nel tempo. Ad esempio, puoi specificare che le animazioni vengano visualizzate linearmente in tutta l'animazione, il che significa che l'animazione si muove in modo uniforme per tutto il tempo, oppure puoi specificare animazioni da utilizzare tempo non lineare, ad esempio utilizzando l'accelerazione o la decelerazione all'inizio o alla fine del l'animazione.

Gli interpolatori nel sistema di animazione ricevono una frazione dagli elementi animati che rappresentano 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 nel android.view.animation package. Se nessuna di queste soddisfa le tue esigenze, puoi implementare l'interfaccia TimeInterpolator e crearne una personalizzata.

Di seguito è riportato un esempio di come l'interpolatore predefinito AccelerateDecelerateInterpolator e LinearInterpolator calcolano le frazioni interpolate. Il valore LinearInterpolator non ha alcun effetto sulla frazione trascorsa. L'elemento AccelerateDecelerateInterpolator si avvia nell'animazione e ne rallenta l'uscita. I seguenti metodi definiscono la logica di 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 tabella seguente rappresenta i valori approssimativi calcolati in base a questi per un'animazione di durata 1000 ms:

ms trascorsi Frazione passata/Frazione interpolata (Lineare) Frazione interpolata (Accelera/Rallenta)
0 0 0
200 0,2 0,1
400 0,4 0,345
600 0,6 0,654
800 0,8 0,9
1000 1 1

Come mostrato nella tabella, LinearInterpolator cambia i valori. alla stessa velocità, 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 di tempo/valore che consente di definire un determinato stato 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 quello di questo 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. Quindi chiami il metodo di fabbrica ofKeyframe() per ottenere un oggetto PropertyValuesHolder. Una volta ottenuto 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 di semplificare l'animazione degli oggetti View e offre alcuni vantaggi rispetto al sistema di animazione delle visualizzazioni. La vista il sistema di animazione ha trasformato gli oggetti View modificando il modo in cui erano stati disegnati. Questo veniva gestito nel contenitore di ogni visualizzazione, perché la visualizzazione stessa non aveva proprietà da manipolare. Di conseguenza, la visualizzazione è stata animata, ma non ha causato alcuna modifica nell'oggetto View stesso. Questo ha comportato 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, le nuove proprietà e le Per eliminare questo svantaggio sono stati aggiunti i metodi getter e setter.

Il sistema di animazione della proprietà puoi animare le viste sullo schermo modificando le proprietà effettive negli oggetti View. Nella in più, le visualizzazioni chiamano anche automaticamente invalidate() per aggiornare la schermata ogni volta che ne vengono modificate le proprietà. Le nuove proprietà nella classe View che facilitano le animazioni delle proprietà sono:

  • translationX e translationY: queste proprietà controllano la posizione della vista come delta dalle coordinate sinistra e superiore impostate dal contenitore layout.
  • rotation, rotationX e rotationY: queste proprietà controllano la rotazione in 2D (proprietà rotation) e in 3D attorno al punto di rotazione.
  • scaleX e scaleY: queste proprietà controllano la scalatura 2D di una vista attorno al suo punto di rotazione.
  • pivotX e pivotY: queste proprietà controllano la posizione delle punto pivot attorno al quale avvengono le trasformazioni di rotazione e scala. Per impostazione predefinita, si trova al centro dell'oggetto.
  • x e y: si tratta di semplici proprietà di utilità per descrivere posizione finale della vista nel relativo contenitore, come una somma dei valori "sinistra" e "in alto" e traslazione X e traslazioneY.
  • alpha: rappresenta la trasparenza alfa nella vista. Per impostazione predefinita, questo valore è 1 (opaco), mentre un valore di 0 indica la massima trasparenza (non visibile).

Per animare una proprietà di un oggetto View, ad esempio il colore o il valore di rotazione, devi solo creare un animatore di proprietà e specificare la proprietà View da animare. Ad esempio:

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

L'elemento ViewPropertyAnimator offre un modo semplice per animare diversi proprietà di un View in parallelo, utilizzando un'unica proprietà Animator sottostante . Si comporta in modo molto simile a un ObjectAnimator, perché modifica valori effettivi delle proprietà della vista, ma è più efficiente quando si animano molte proprietà una volta sola. Inoltre, il codice per l'utilizzo di ViewPropertyAnimator è molto più conciso e facile da leggere. Gli snippet di codice seguenti 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 visualizzazione.

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 gli sviluppatori Android corrispondenti blog post.

Dichiara le animazioni in XML

Il sistema di animazione delle proprietà ti consente di dichiarare le animazioni delle proprietà tramite XML 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 animazione della vista precedente, 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 il seguenti tag XML:

Per trovare gli attributi che puoi utilizzare nella dichiarazione XML, consulta la sezione Animazione Google Cloud. L'esempio seguente riproduce i due insiemi di animazioni di oggetti sequenzialmente, con il primo insieme nidificato che riproduce contemporaneamente 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 gonfiare le risorse XML nel codice in un oggetto AnimatorSet e impostare gli oggetti di destinazione per tutte le animazioni prima di avviare l'insieme di animazioni. Per comodità, la chiamata a setTarget() imposta un singolo oggetto target per tutti gli elementi secondari di AnimatorSet. Il seguente codice mostra come eseguire questa operazione:

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 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 usare l'elemento ValueAnimator precedente nel codice, devi gonfiare l'oggetto, aggiungi un AnimatorUpdateListener, ottenere il valore aggiornato dell'animazione e utilizzarlo in una proprietà di una delle viste, come mostrato 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 di animazione.

Potenziali effetti sulle prestazioni dell'interfaccia utente

Gli animatori che aggiornano l'interfaccia utente causano un lavoro di rendering aggiuntivo per ogni frame in cui viene eseguita l'animazione. Per questo motivo, l'utilizzo di animazioni che richiedono molte risorse può influire negativamente sul rendimento della tua app.

Il lavoro necessario per animare l'interfaccia utente viene aggiunto alla fase di animazione della pipeline di rendering. Per scoprire se le animazioni influiscono sulle prestazioni della tua app, attiva Profila il rendering GPU e monitora la fase di animazione. Per ulteriori informazioni, consulta la sezione Rendering GPU del profilo procedura dettagliata.