Personalizza le animazioni

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

Personalizza le animazioni con il parametro AnimationSpec

La maggior parte delle API di animazione consente agli sviluppatori di personalizzare le specifiche delle animazioni 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)
)

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

Crea animazioni basate sulla fisica con spring

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

dampingRatio definisce la frequenza di rimbalzo della molla. Il valore predefinito è Spring.DampingRatioNoBouncy.

Figura 1. Impostazione di diversi rapporti di smorzamento della molla.

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

Figura 2. Impostazione di una diversa rigidità della molla

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

spring può gestire le interruzioni in modo più fluido rispetto ai tipi AnimationSpec basati sulla durata perché garantisce la continuità della velocità quando il valore target cambia durante le animazioni. 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 l'avanzamento, puoi notare che l'uso di tween non risponde in modo fluido come se usi spring.

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

Esegui l'animazione tra i valori iniziali e finali con una curva di interpolazione con tween

L'elemento tween si anima tra i valori iniziale e finale nel valore durationMillis specificato utilizzando una curva di easing. tween è l'abbreviazione della parola tra, in quanto 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
    )
)

Consulta la sezione Facilitazione per ulteriori informazioni.

Applica animazioni a valori specifici in determinati momenti con keyframes

L'animazione di keyframes si basa sui valori dello snapshot specificati in timestamp diversi della durata dell'animazione. In qualsiasi momento, il valore dell'animazione viene interpolato tra due valori per i fotogrammi chiave. Per ognuno di questi fotogrammi chiave è possibile specificare l'Easing per determinare la curva di interpolazione.

È facoltativo specificare i valori a 0 ms e alla relativa durata. Se non specifichi questi valori, vengono utilizzati in modo predefinito i valori di inizio e fine dell'animazione, rispettivamente.

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

Ripeti un'animazione con repeatable

repeatable esegue ripetutamente un'animazione basata sulla durata (ad esempio tween o keyframes) finché non raggiunge 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
    )
)

Ripeti un'animazione all'infinito con infiniteRepeatable

infiniteRepeatable è come repeatable, ma si ripete per una quantità infinita di iterazioni.

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

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.

Allinea immediatamente al valore finale con snap

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

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

Impostare una funzione di easing personalizzata

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

L'easing è infatti una funzione che prende un valore di frazione compreso tra 0 e 1,0 e restituisce un valore in virgola mobile. Il valore restituito può essere al di fuori del limite per rappresentare un superamento o un superamento. È possibile creare un emulatore personalizzato 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
        )
    )
    // ……
}

Compose offre diverse funzioni Easing integrate adatte alla maggior parte dei casi d'uso. Consulta Velocità - Material Design per ulteriori informazioni su cosa Easing utilizzare in base al tuo scenario.

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

Anima tipi di dati personalizzati convertendo in e da AnimationVector

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

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

Color è essenzialmente un insieme di quattro valori, rosso, verde, blu e alfa, pertanto Color viene convertito in un AnimationVector4D contenente quattro valori a virgola mobile. In questo modo, ogni tipo di dati utilizzato nelle animazioni viene convertito in AnimationVector1D, AnimationVector2D, AnimationVector3D o AnimationVector4D a seconda della sua dimensionalità. Ciò consente di animare diversi componenti dell'oggetto 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 per 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 tuo tipo di dati personalizzati in questo modo:

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)
            }
        )
    )
}

Il seguente elenco include alcuni VectorConverter integrati: