Molte delle API di animazione accettano comunemente parametri per personalizzarne il 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 la creazione di diversi tipi di animazione.
Creare animazioni basate sulla fisica con spring
spring crea un'animazione basata sulla fisica tra i valori di inizio e fine. Accetta due parametri: dampingRatio e stiffness.
dampingRatio definisce la reattività della molla. Il valore predefinito è Spring.DampingRatioNoBouncy.
stiffness definisce la velocità con cui la molla deve spostarsi verso il valore finale. Il valore predefinito è Spring.StiffnessMedium.
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ù 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 la sua esecuzione, puoi notare che l'utilizzo di tween non risponde in modo fluido come l'utilizzo di spring.
tween e spring per l'animazione e interruzione.Animare tra i valori di inizio e fine con la curva di interpolazione con tween
tween anima tra i valori di inizio e fine per il valore durationMillis specificato utilizzando una curva di interpolazione. tween è l'abbreviazione della parola "between" (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 saperne di più, consulta Interpolazione.
Animare a valori specifici in determinati momenti con keyframes
keyframes anima in base ai valori degli snapshot specificati in diversi timestamp durante la durata dell'animazione. In un determinato momento, il valore dell'animazione verrà interpolato tra due valori di fotogrammi chiave. Per ognuno di questi fotogrammi chiave, è possibile specificare l'interpolazione per determinare la curva di interpolazione.
È facoltativo specificare i valori a 0 ms e al momento della durata. Se non specifichi questi valori, vengono impostati come predefiniti rispettivamente i valori di inizio e fine 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" )
Animare tra i fotogrammi chiave in modo fluido con keyframesWithSplines
Per creare un'animazione che segue una curva uniforme durante la transizione tra i
valori, puoi utilizzare keyframesWithSplines anziché keyframes specifiche di animazione.
val offset by animateOffsetAsState( targetValue = Offset(300f, 300f), animationSpec = keyframesWithSpline { durationMillis = 6000 Offset(0f, 0f) at 0 Offset(150f, 200f) atFraction 0.5f Offset(0f, 100f) atFraction 0.7f } )
I fotogrammi chiave basati su spline sono particolarmente utili per il movimento 2D degli elementi sullo schermo.
I seguenti video mostrano le differenze tra keyframes e
keyframesWithSpline dato lo stesso insieme di coordinate x, y che un cerchio
deve seguire.
keyframes
|
keyframesWithSplines
|
|---|---|
Come puoi vedere, i fotogrammi chiave basati su spline offrono transizioni più fluide tra i punti, in quanto utilizzano curve di Bézier per animare in modo fluido tra gli elementi. Questa specifica è utile per un'animazione preimpostata. Tuttavia, se lavori con punti basati sull'utente, è preferibile utilizzare le molle per ottenere una fluidità simile tra i punti, perché sono interrompibili.
Ripetere un'animazione con repeatable
repeatable esegue ripetutamente un'animazione basata sulla durata (ad esempio tween o keyframes) fino a raggiungere il numero di iterazioni specificato. Puoi passare il parametro repeatMode per specificare se l'animazione deve essere ripetuta 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" )
Ripetere 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à sottoposto a rendering utilizzando il valore iniziale di ogni valore animato.
Passare immediatamente al valore finale con snap
snap è una 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 interpolazione 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 di animazione può accelerare e rallentare, anziché spostarsi a una velocità costante. La frazione è un valore compreso tra 0 (inizio) e 1,0 (fine) che indica il punto corrente dell'animazione.
L'interpolazione è in realtà una funzione che accetta un valore di frazione compreso tra 0 e 1,0 e restituisce un valore float. Il valore restituito può essere al di fuori del limite per rappresentare un overshoot o un undershoot. È possibile creare un'interpolazione personalizzata come nel 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 saperne di più su quale interpolazione utilizzare a seconda dello scenario, consulta Velocità - Material Design.
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearEasingLinearEasingCubicBezierEasing- Scopri di più
Animare i tipi di dati personalizzati convertendo da e verso 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 di animazione viene rappresentato come AnimationVector. Il valore viene convertito in AnimationVector e viceversa da un TwoWayConverter corrispondente, in modo che il sistema di animazione principale possa gestirli in modo uniforme. Ad esempio, un Int è rappresentato come AnimationVector1D che contiene un singolo valore float.
TwoWayConverter per Int è simile al seguente:
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 AnimationVector4D che contiene 4 valori float. In questo modo, ogni tipo di dati 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, ognuno 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.
Se vuoi aggiungere il supporto per un nuovo tipo di dati come valore di animazione, puoi creare il tuo TwoWayConverter e fornirlo all'API. Ad esempio, puoi utilizzare animateValueAsState per animare il tuo tipo di dati personalizzato nel seguente 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) } ), label = "size" ) }
Il seguente elenco include alcuni VectorConverter integrati:
Color.VectorConverterDp.VectorConverterOffset.VectorConverterInt.VectorConverterFloat.VectorConverterIntSize.VectorConverter
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Animazioni basate sul valore
- Sviluppo di codice iterativo {:#iterative-code-dev }
- Animazioni in Compose