Animazione dei movimenti tramite fisica primaverile

Prova il metodo Scrivi
Jetpack Compose è il toolkit consigliato per la UI per Android. Scopri come utilizzare le animazioni in Compose.

Basati sulla fisica è azionato dalla forza. La forza elastica è una di queste forze che guida interattività e movimento. Una forza della molla ha le seguenti proprietà: smorzamento e rigidità. In un'animazione a molla, il valore e la velocità viene calcolata in base alla forza della molla applicata su frame.

Se vuoi che le animazioni dell'app rallentino in una sola direzione, valuta l'utilizzo di un modello di attribuzione animazione flangiata .

Ciclo di vita di un'animazione primaverile

In un'animazione a molla, SpringForce consente di personalizzare la rigidità della molla, il rapporto di smorzamento e posizione finale. Non appena inizia l'animazione, la forza della molla si aggiorna il valore e la velocità dell'animazione su ciascun frame. L'animazione continua finché la forza della molla non raggiunge un equilibrio.

Ad esempio, se trascini l'icona di un'app sullo schermo e poi la rilasci sollevando il dito dall'icona, l'icona torna alla sua originale posto da una forza invisibile ma familiare.

La figura 1 mostra un effetto molla simile. Il segno più (+) il centro del cerchio indica la forza applicata da un gesto di tocco.

Rilascio di primavera
Figura 1. Effetto rilascio primaverile
.

Creare un'animazione primaverile

I passaggi generali per creare un'animazione a molla per l'applicazione sono come segue:

Le sezioni seguenti illustrano la procedura generale per la costruzione di una molla dell'animazione in dettaglio.

Aggiungi la libreria di supporto

Per utilizzare la libreria di supporto basata sulla fisica, devi aggiungere la libreria di supporto al tuo progetto come segue:

  1. Apri il file build.gradle del modulo dell'app.
  2. Aggiungi la libreria di supporto alla sezione dependencies.

    Alla moda

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

    Kotlin

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

    Per visualizzare le versioni correnti di questa libreria, consulta le informazioni su Animazione dinamica nella pagina delle versioni.

Creare un'animazione primaverile

Il corso SpringAnimation ti consente di creare un'animazione a molla per un oggetto. Per creare un'animazione a molla, devi crea un'istanza di SpringAnimation e fornisce un oggetto, la proprietà di un oggetto che vuoi animare e una posizione finale della primavera facoltativa nel punto in cui vuoi far riposare l'animazione.

Nota: al momento della creazione di un'animazione primaverile, la posizione della molla è facoltativa. Tuttavia, deve essere definito prima di avviare l'animazione.

Kotlin

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

Java

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

L'animazione a molla può animare le visualizzazioni sullo schermo modificando il valore le proprietà effettive degli oggetti della vista. Le seguenti visualizzazioni sono disponibili in il sistema:

  • ALPHA: Rappresenta la trasparenza alpha della vista. Il valore è 1 (opaco) di predefinito, con un valore pari a 0 che rappresenta la massima trasparenza (non visibile).
  • TRANSLATION_X, TRANSLATION_Y e TRANSLATION_Z: queste le proprietà controllano la posizione della vista sotto forma di delta a sinistra coordinate, superiore ed elevazione, che sono impostate dal relativo layout containerizzato.
  • ROTATION, ROTATION_X e ROTATION_Y: queste controllano la rotazione in 2D (proprietà rotation) e 3D intorno al punto pivot.
  • SCROLL_X e SCROLL_Y: questi indicano l'offset di scorrimento dell'origine a sinistra e il bordo superiore in pixel. Indica anche la posizione in termini di quanto sia la pagina hai fatto scorrere la pagina.
  • SCALE_X e SCALE_Y: questi controllano il ridimensionamento 2D di una vista intorno al suo punto pivot.
  • X, Y e Z: sono di base di utilità per descrivere la posizione finale della vista containerizzato.

Registra listener

La classe DynamicAnimation fornisce due ascoltatori: OnAnimationUpdateListener e OnAnimationEndListener. Questi listener ascoltano gli aggiornamenti nell'animazione, ad esempio quando c'è un modifica nel valore dell'animazione e alla fine dell'animazione.

Listener di aggiornamento onAnimation

Quando vuoi animare più visualizzazioni per creare un'animazione concatenata, puoi configurare OnAnimationUpdateListener di ricevere un callback ogni volta che viene apportata una modifica alla visualizzazione corrente proprietà. Il callback comunica all'altra vista di aggiornare la posizione della molla. in base alla modifica apportata alla proprietà della vista corrente. Per registrare il listener, segui questi passaggi:

  1. Chiama il addUpdateListener() e allega il listener all'animazione.

    Nota: devi registrare l'aggiornamento prima dell'inizio dell'animazione. Però, il listener di aggiornamenti dovrebbe essere registrato solo se hai bisogno di un aggiornamento per frame del valore dell'animazione modifiche. Un listener di aggiornamenti impedisce all'animazione di in esecuzione su un thread separato.

  2. Esegui l'override di onAnimationUpdate() per notificare al chiamante la modifica dell'oggetto corrente. La il seguente codice di esempio illustra l'utilizzo complessivo OnAnimationUpdateListener.

Kotlin

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

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

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

Java

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

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

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

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

anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

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

Listener fineanimazione

OnAnimationEndListener avvisa la fine di un'animazione. Puoi impostare il listener in modo che riceva ogni volta che l'animazione raggiunge l'equilibrio o viene annullata. A registrare il listener, segui questi passaggi:

  1. Chiama il addEndListener() e allega il listener all'animazione.
  2. Esegui l'override di onAnimationEnd() per ricevere una notifica ogni volta che un'animazione raggiunge l'equilibrio o viene annullato.

Rimuovi listener

Per non ricevere più i callback di aggiornamento e di fine animazione: chiama removeUpdateListener() e removeEndListener() rispettivamente.

Imposta il valore iniziale dell'animazione

Per impostare il valore iniziale dell'animazione, richiama il metodo setStartValue() e passiamo il valore iniziale dell'animazione. Se non imposti valore iniziale, l'animazione utilizza il valore corrente della proprietà dell'oggetto come valore iniziale.

Imposta l'intervallo di valori dell'animazione

Puoi impostare il valore minimo e massimo dell'animazione quando vuoi limita il valore della proprietà a un determinato intervallo. Inoltre, è utile per controllare se animate proprietà che hanno un intervallo intrinseco, come alfa (da 0 a 1).

  • Per impostare il valore minimo, richiama il metodo setMinValue() e trasmetti il valore minimo della proprietà.
  • Per impostare il valore massimo, chiama setMaxValue() e trasmetti il valore massimo della proprietà.

Entrambi i metodi restituiscono l'animazione per la quale è stato impostato il valore.

Nota: se hai impostato il valore iniziale e hai definito un intervallo di valori dell'animazione, assicurati che il valore iniziale sia compreso tra il valore minimo e l'intervallo di valori massimo.

Imposta velocità iniziale

La velocità iniziale definisce la velocità di variazione della proprietà dell'animazione all'inizio dell'animazione. La velocità iniziale predefinita è impostata su zero pixel al secondo. Puoi impostare la velocità con la velocità del tocco gesti o utilizzando un valore fisso come velocità iniziale. Se scegli di forniscono un valore fisso, consigliamo di definire il valore in dp al secondo e quindi convertirla in pixel al secondo. Definizione del valore in dp al secondo permette che la velocità sia indipendente dalla densità e dai fattori di forma. Per ulteriori informazioni informazioni sulla conversione del valore in pixel al secondo, fai riferimento alle Conversione dei dp al secondo in pixel al secondo .

Per impostare la velocità, chiama la funzione setStartVelocity() e passiamo la velocità in pixel al secondo. Il metodo restituisce l'oggetto di forza della molla su cui è impostata la velocità.

Nota: utilizza lo GestureDetector.OnGestureListener o Metodi della classe VelocityTracker per recuperare e calcolare la velocità dei gesti tattili.

Kotlin

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

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Compute velocity in the unit pixel/second
vt.computeCurrentVelocity(1000);
float velocity = vt.getYVelocity();
anim.setStartVelocity(velocity);

Conversione dei dp al secondo in pixel al secondo

La velocità di una molla deve essere espressa in pixel al secondo. Se scegli di fornire un valore fisso come inizio della velocità, fornisci il valore in dp al secondo e quindi convertirla in pixel al secondo. Per le conversioni, utilizza la classe applyDimension() della classe TypedValue. Consulta le il seguente codice campione:

Kotlin

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

Java

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

Impostare le proprietà della molla

La classe SpringForce definisce il getter e i metodi di setter per ciascuna delle proprietà della molla, come lo smorzamento rapporto e rigidità. Per impostare le proprietà molla, è importante recupera l'oggetto forza molla o crea una forza molla personalizzata su puoi impostare le proprietà. Per ulteriori informazioni sulla creazione di un'istanza forza della molla, fai riferimento Creazione di una forza elastica personalizzata .

Suggerimento: quando utilizzi i metodi del setter, puoi: crea una catena di metodi poiché tutti i metodi di impostazione restituiscono la forza della molla .

Rapporto di smorzamento

Il rapporto di smorzamento descrive una riduzione graduale dell'oscillazione della molla. Di Utilizzando il rapporto di smorzamento, puoi definire la velocità di decadimento delle oscillazioni da un rimbalzo all'altro. Esistono quattro modi diversi per attenuare primavera:

  • Si verifica un sovrasmorzamento quando il rapporto di smorzamento è maggiore di uno. Consente di l'oggetto torna delicatamente nella posizione di riposo.
  • Uno smorzamento critico si verifica quando il rapporto di smorzamento è pari a 1. Consente di l'oggetto ritorna nella posizione di riposo entro il tempo più breve.
  • Si verifica una scarsa smorzamento quando il rapporto di smorzamento è inferiore a uno. Consente di l'oggetto supera più volte passando la posizione di riposo, raggiunge gradualmente la posizione di riposo.
  • Non smorzato si verifica quando il rapporto di smorzamento è pari a zero. Consente al oscillano all'infinito.

Per aggiungere il rapporto di smorzamento alla molla:

  1. Chiama il getSpring() per recuperare la molla e sommare il rapporto di smorzamento.
  2. Chiama il setDampingRatio() e passa il rapporto di smorzamento che vuoi aggiungere alla molla. La restituisce l'oggetto forza molla su cui è impostato il rapporto di smorzamento.

    Nota: il rapporto di smorzamento deve essere un numero non negativo. Se imposti il rapporto di smorzamento su zero, la molla non raggiungere mai la posizione di riposo. In altre parole, oscilla per sempre.

Nel sistema sono disponibili le seguenti costanti del rapporto di smorzamento:

Figura 2: rimbalzo elevato

Figura 3: rimbalzo medio

Figura 4: rimbalzo basso

Figura 5: nessun rimbalzo

Il rapporto di smorzamento predefinito è impostato su DAMPING_RATIO_MEDIUM_BOUNCY.

Kotlin

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

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Setting the damping ratio to create a low bouncing effect.
anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY);
…

Rigidità

La rigidità definisce la costante molla, che misura la forza della primavera. Una molla rigida applica più forza all'oggetto attaccato quando la molla non è in posizione di riposo. Per aumentare la rigidità della molla, segui questi passaggi:

  1. Chiama il getSpring() per recuperare la molla e aggiungere la rigidità.
  2. Chiama il setStiffness() e passa il valore di rigidità che vuoi aggiungere alla molla. La restituisce l'oggetto forza molla su cui è impostata la rigidità.

    Nota: la rigidità deve essere un numero positivo.

Nel sistema sono disponibili le seguenti costanti di rigidità:

Figura 6: rigidità elevata

Figura 7: rigidità media

Figura 8: rigidità bassa

Figura 9: rigidità molto bassa

La rigidità predefinita è impostata su STIFFNESS_MEDIUM.

Kotlin

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

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Setting the spring with a low stiffness.
anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW);
…

Creare una forza elastica personalizzata

Puoi creare una forza elastica personalizzata in alternativa all'uso di quella predefinita forza della molla. La forza elastica personalizzata ti consente di condividere la stessa forza elastica in più animazioni a molla. Una volta creata la molla , puoi impostare proprietà come il rapporto di smorzamento e la rigidità.

  1. Crea un oggetto SpringForce.

    SpringForce force = new SpringForce();

  2. Assegna le proprietà chiamando i rispettivi metodi. Puoi anche per creare una catena di metodi.

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

  3. Chiama il setSpring() per impostare la molla sull'animazione.

    setSpring(force);

Avvia animazione

Esistono due modi per avviare un'animazione primaverile: chiamando il metodo start() o chiamando il animateToFinalPosition() . Entrambi i metodi devono essere chiamati sul thread principale.

animateToFinalPosition() esegue due attività:

  • Imposta la posizione finale della molla.
  • Avvia l'animazione, se non è stata avviata.

Poiché il metodo aggiorna la posizione finale della molla e inizia dell'animazione se necessario, puoi chiamare questo metodo in qualsiasi momento per modificare il corso di un'animazione. Ad esempio, in un'animazione di primavera concatenata, l'animazione di una visualizzazione dipende da un'altra. Per un'animazione di questo tipo, è più necessario utilizzare animateToFinalPosition() . Se utilizzi questo metodo in un'animazione a molla concatenata, non è necessario devi preoccuparti se l'animazione che vuoi aggiornare dopo è attualmente in esecuzione.

La figura 10 illustra un'animazione a molla concatenata, in cui l'animazione di una dipende da un'altra visualizzazione.

Demo sulla molla incatenata
Figura 10. Demo sulla molla incatenata
.

Per utilizzare animateToFinalPosition() , richiama il metodo animateToFinalPosition() e passiamo la posizione di riposo della molla. Puoi anche impostare le altre posizione della molla richiamando setFinalPosition() .

Il metodo start() non impostare subito il valore della proprietà sul valore iniziale. La proprietà il valore cambia a ogni impulso dell'animazione, che si verifica prima del superamento dell'estrazione. Di conseguenza, le modifiche vengono riportate nel frame successivo, come se i valori vengono impostati immediatamente.

Kotlin

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

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Starting the animation
anim.start();
…

Annulla animazione

Puoi annullare l'animazione o andare alla fine dell'animazione. Situazione ideale in cui devi annullare o andare alla fine dell'ammirazione si verifica quando un utente richiede che l'animazione venga terminata immediatamente. Questo è principalmente quando un utente esce bruscamente dall'app o la vista diventa invisibile.

Esistono due metodi che puoi utilizzare per terminare l'animazione. Il metodo cancel() termina l'animazione in corrispondenza del valore in cui si trova. La Metodo skipToEnd() ignora l'animazione per passare al valore finale e la termina.

Prima di poter terminare l'animazione, è importante controllare lo stato della primavera. Se lo stato non è smorzato, l'animazione non potrà mai raggiungere la posizione di riposo. Per controllare lo stato della molla, chiama la funzione canSkipToEnd(). Se la molla è smorzata, il metodo restituisce true, altrimenti false.

Quando conosci lo stato della molla, puoi terminare un'animazione utilizzando skipToEnd() o il metodo Metodo cancel(). La cancel() metodo deve essere chiamato solo nel thread principale.

Nota: in generale, Cause del metodo skipToEnd() un salto visivo.