Personalizza le animazioni

Molte API di animazione accettano comunemente parametri per personalizzare il loro comportamento.

Personalizzare le animazioni con il parametro AnimationSpec

La maggior parte delle API di animazione consente agli sviluppatori di personalizzare le specifiche di animazione tramite un parametro AnimationSpec facoltativo.

val alpha: Float by animateFloatAsState(
    targetValue = if (enabled) 1f else 0.5f,
    // Configure the animation duration and easing.
    animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing),
    label = "alpha"
)

Esistono diversi tipi di AnimationSpec per creare diversi tipi di animazioni.

Creare animazioni basate sulla fisica con spring

spring crea un'animazione basata sulla fisica tra i valori iniziale e finale. Richiede 2 parametri: dampingRatio e stiffness.

dampingRatio definisce l'elasticità della molla. Il valore predefinito è Spring.DampingRatioNoBouncy.

Figura 1. Impostazione di diversi rapporti di smorzamento delle molle.

stiffness definisce la velocità con cui la molla deve muoversi verso il valore finale. Il valore predefinito è Spring.StiffnessMedium.

Figura 2. Impostazione di una rigidità della molla diversa

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioHighBouncy,
        stiffness = Spring.StiffnessMedium
    ),
    label = "spring spec"
)

spring può gestire le interruzioni in modo più agevole rispetto ai tipi spring basati sulla durata perché garantisce la continuità della velocità quando il valore target cambia durante le animazioni.AnimationSpec spring viene utilizzato come AnimationSpec predefinito da molte API di animazione, come animate*AsState e updateTransition.

Ad esempio, se applichiamo una configurazione spring alla seguente animazione basata sul tocco dell'utente, quando interrompi l'animazione durante il suo avanzamento, puoi notare che l'utilizzo di tween non risponde in modo fluido come l'utilizzo di spring.

Figura 3. Impostazione delle specifiche tween rispetto a spring per l'animazione e interruzione.

Applica un'animazione tra i valori iniziale e finale con una curva di easing con tween

tween anima i valori iniziale e finale in base al valore durationMillis specificato utilizzando una curva di easing. tween è l'abbreviazione della parola tra, in quanto si trova tra due valori.

Puoi anche specificare delayMillis per posticipare l'inizio dell'animazione.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing
    ),
    label = "tween delay"
)

Per ulteriori informazioni, consulta la sezione Effetti di transizione.

Esegui l'animazione fino a valori specifici in determinati momenti con keyframes

keyframes si anima in base ai valori dello snapshot specificati in diversi timestamp durante la durata dell'animazione. In qualsiasi momento, il valore dell'animazione verrà interpolato tra due valori di fotogramma chiave. Per ciascuno di questikeyframe, puoi specificare la funzionalità Easing per determinare la curva di interpolazione.

È facoltativo specificare i valori a 0 ms e al momento della durata. Se non li specifichi, per impostazione predefinita vengono utilizzati i valori iniziale e finale dell'animazione.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = keyframes {
        durationMillis = 375
        0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 using FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.4f at 225 // ms
    },
    label = "keyframe"
)

Ripeti un'animazione con repeatable

repeatable esegue un'animazione basata sulla durata (ad esempio tween o keyframes) ripetutamente fino a raggiungere il numero di iterazioni specificato. Puoi passare il parametro repeatMode per specificare se l'animazione deve ripetersi iniziando dall'inizio (RepeatMode.Restart) o dalla fine (RepeatMode.Reverse).

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = repeatable(
        iterations = 3,
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "repeatable spec"
)

Ripeti un'animazione all'infinito con infiniteRepeatable

infiniteRepeatable è simile a repeatable, ma si ripete per un numero infinito di iterazioni.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "infinite repeatable"
)

Nei test che utilizzano ComposeTestRule, le animazioni che utilizzano infiniteRepeatable non vengono eseguite. Il componente verrà visualizzato utilizzando il valore iniziale di ogni valore animato.

Passa immediatamente al valore di fine con snap

snap è un AnimationSpec speciale che passa immediatamente il valore al valore finale. Puoi specificare delayMillis per ritardare l'inizio dell'animazione.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = snap(delayMillis = 50),
    label = "snap spec"
)

Impostare una funzione di attenuazione personalizzata

Le operazioni AnimationSpec basate sulla durata (ad esempio tween o keyframes) utilizzano Easing per regolare la frazione di un'animazione. In questo modo, il valore animato può accelerare e rallentare, anziché muoversi a una velocità costante. La frazione è un valore compreso tra 0 (inizio) e 1,0 (fine) che indica il punto corrente dell'animazione.

La funzione di transizione è in realtà una funzione che prende un valore frazionario compreso tra 0 e 1,0 e restituisce un valore float. Il valore restituito può essere esterno al confine per rappresentare un overshoot o un undershoot. È possibile creare un'animazione personalizzata come il codice riportato di seguito.

val CustomEasing = Easing { fraction -> fraction * fraction }

@Composable
fun EasingUsage() {
    val value by animateFloatAsState(
        targetValue = 1f,
        animationSpec = tween(
            durationMillis = 300,
            easing = CustomEasing
        ),
        label = "custom easing"
    )
    // ……
}

Compose fornisce diverse funzioni Easing integrate che coprono la maggior parte dei casi d'uso. Per ulteriori informazioni su che cosa si intende per facilità d'uso a seconda dello scenario, consulta Velocità - Material Design.

  • FastOutSlowInEasing
  • LinearOutSlowInEasing
  • FastOutLinearEasing
  • LinearEasing
  • CubicBezierEasing
  • Scopri di più

Anima i tipi di dati personalizzati convertendoli in AnimationVector e da AnimationVector

Per impostazione predefinita, la maggior parte delle API di animazione di Compose supporta Float, Color, Dp e altri tipi di dati di base come valori di animazione, ma a volte è necessario animare altri tipi di dati, inclusi quelli personalizzati. Durante l'animazione, qualsiasi valore animato è rappresentato come AnimationVector. Il valore viene convertito in un AnimationVector e viceversa da un TwoWayConverter corrispondente in modo che il sistema di animazione di base possa gestirli in modo uniforme. Ad esempio, un Int viene rappresentato come un AnimationVector1D contenente un singolo valore in virgola mobile. TwoWayConverter per Int ha questo aspetto:

val IntToVector: TwoWayConverter<Int, AnimationVector1D> =
    TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })

Color è essenzialmente un insieme di 4 valori, rosso, verde, blu e alfa, quindi Color viene convertito in un AnimationVector4D contenente 4 valori float. In questo modo, ogni tipo di dato utilizzato nelle animazioni viene convertito in AnimationVector1D, AnimationVector2D, AnimationVector3D o AnimationVector4D a seconda della sua dimensionalità. In questo modo, i diversi componenti dell'oggetto possono essere animati in modo indipendente, ciascuno con il proprio monitoraggio della velocità. È possibile accedere ai convertitori integrati per i tipi di dati di base utilizzando convertitori come Color.VectorConverter o Dp.VectorConverter.

Quando vuoi aggiungere il supporto di un nuovo tipo di dati come valore animato, puoi creare il tuo TwoWayConverter e fornirlo all'API. Ad esempio, puoi utilizzare animateValueAsState per animare il tipo di dati personalizzati come segue:

data class MySize(val width: Dp, val height: Dp)

@Composable
fun MyAnimation(targetSize: MySize) {
    val animSize: MySize by animateValueAsState(
        targetSize,
        TwoWayConverter(
            convertToVector = { size: MySize ->
                // Extract a float value from each of the `Dp` fields.
                AnimationVector2D(size.width.value, size.height.value)
            },
            convertFromVector = { vector: AnimationVector2D ->
                MySize(vector.v1.dp, vector.v2.dp)
            }
        ),
        label = "size"
    )
}

Il seguente elenco include alcuni VectorConverter integrati: