Animazioni con gesti e molle
Movimenti naturali basati sulla fisica
Animazioni con gesti e molle è una lezione Android Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Android Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Android Academy include 4 lezioni in totale.
Movimento interattivo e fisico
Le animazioni più coinvolgenti rispondono al dito dell'utente e danno la sensazione di oggetti reali, con inerzia e rimbalzo. Per crearle, si combinano gesti e animazioni basate sulla fisica.
Questa lezione tratta Animatable, gli spring, il decadimento del fling e il collegamento con i gesti di trascinamento per realizzare un'interfaccia naturale e interattiva.
Animatable: controllo di basso livello
Mentre animate*AsState reagisce allo stato, Animatable offre un controllo imperativo. Ne conserva un'istanza in remember e la gestisce da una coroutine con chiamate come animateTo o snapTo.
Questa è la base del movimento guidato dai gesti.
@Composable
fun BounceOnClick() {
val scale = remember { Animatable(1f) }
val scope = rememberCoroutineScope()
Box(
Modifier
.graphicsLayer { scaleX = scale.value; scaleY = scale.value }
.clickable {
scope.launch {
scale.animateTo(1.3f, spring())
scale.animateTo(1f, spring())
}
}
)
}Spring: dampingRatio e stiffness
Una specifica spring è definita da due valori:
- dampingRatio - indica quanto rimbalza. Un valore più basso produce più rimbalzi;
1f(smorzamento critico) non supera l'obiettivo. - stiffness - indica la velocità. Un valore più alto raggiunge l'obiettivo più rapidamente.
Compose fornisce costanti come Spring.DampingRatioMediumBouncy e Spring.StiffnessLow, quindi raramente è necessario utilizzare valori numerici grezzi.
val spec = spring<Float>(
dampingRatio = Spring.DampingRatioLowBouncy,
stiffness = Spring.StiffnessMedium
)
// later, inside a coroutine:
// offset.animateTo(targetValue = 0f, animationSpec = spec)Rilevare i gesti di trascinamento
Per rendere interattivo il movimento, si leggono gli input tattili. Modifier.pointerInput con detectDragGestures segnala gli spostamenti durante il trascinamento mentre l'utente muove il dito.
Si accumulano questi spostamenti in un offset e lo si applica al composable.
@Composable
fun Draggable() {
var offsetX by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), 0) }
.size(80.dp)
.background(Color.Red)
.pointerInput(Unit) {
detectDragGestures { change, drag ->
change.consume()
offsetX += drag.x
}
}
)
}Tornare indietro con una molla
Combini il trascinamento con Animatable per ottenere un effetto di "ritorno a scatto". Durante il trascinamento, usi snapTo per portare istantaneamente l'elemento nella posizione del dito; al rilascio, usi animateTo(0f) con una molla, così l'elemento rimbalza tornando alla posizione iniziale.
@Composable
fun SnapBack() {
val offsetX = remember { Animatable(0f) }
val scope = rememberCoroutineScope()
Box(
Modifier
.offset { IntOffset(offsetX.value.roundToInt(), 0) }
.size(80.dp)
.background(Color.Blue)
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, drag ->
change.consume()
scope.launch { offsetX.snapTo(offsetX.value + drag.x) }
},
onDragEnd = {
scope.launch { offsetX.animateTo(0f, spring()) }
}
)
}
)
}Lanciare con la velocità
Un lancio realistico continua a muoversi dopo che il dito si solleva. Tieni traccia della velocità con un VelocityTracker, quindi passala a animateDecay, così l'elemento rallenta gradualmente fino a fermarsi in modo naturale usando un DecayAnimationSpec basato sull'attrito.
val decay = rememberSplineBasedDecay<Float>()
// on drag end, with measured velocity:
// scope.launch {
// offsetX.animateDecay(
// initialVelocity = velocity,
// animationSpec = decay
// )
// }Swipe per chiudere con gli ancoraggi
Per i gesti di swipe con posizioni di riposo fisse, come lo swipe per chiudere, anchoredDraggable porta l'elemento agli ancoraggi definiti. Dichiari gli stati e le relative posizioni in pixel, mentre Compose gestisce l'animazione a molla tra di essi.
enum class DragValue { Start, End }
val state = remember {
AnchoredDraggableState(
initialValue = DragValue.Start,
anchors = DraggableAnchors {
DragValue.Start at 0f
DragValue.End at 300f
}
)
}Animazioni infinite e ripetute
Per movimenti continui, come un punto pulsante o un effetto shimmer di caricamento, usa rememberInfiniteTransition con infiniteRepeatable. Imposta RepeatMode su Reverse per un movimento avanti e indietro, oppure su Restart per ripetere dall'inizio.
@Composable
fun Pulse() {
val transition = rememberInfiniteTransition(label = "pulse")
val scale by transition.animateFloat(
initialValue = 1f,
targetValue = 1.2f,
animationSpec = infiniteRepeatable(
animation = tween(700),
repeatMode = RepeatMode.Reverse
),
label = "scale"
)
Box(Modifier.graphicsLayer { scaleX = scale; scaleY = scale })
}Combinare gesto e molla
Il modello interattivo per eccellenza: trascinare per muovere, rilasciare per assestare. Tieni traccia della velocità durante il trascinamento, quindi esegui un lancio con animateDecay oppure assesta l'elemento verso un ancoraggio con una spring, in base alla distanza o alla velocità.
È esattamente così che bottom sheet, caroselli e schede chiudibili risultano così naturali.
// pattern:
// 1) onDrag -> animatable.snapTo(current + delta)
// 2) onDragEnd -> if (fast) animatable.animateDecay(velocity, decay)
// else animatable.animateTo(nearestAnchor, spring())Assestamento con una molla in puro Kotlin
Per capire come si assesta una molla, ecco un semplice ciclo scritto in puro Kotlin. Applica una forza di richiamo verso l'obiettivo e smorza la velocità a ogni passaggio: è la stessa idea che Compose esegue a ogni frame.
fun main() {
var pos = 0f
var vel = 0f
val target = 200f
val stiffness = 0.2f
val damping = 0.75f
repeat(8) { step ->
vel = (vel + (target - pos) * stiffness) * damping
pos += vel
println("step $step pos=${"%.1f".format(pos)}")
}
}Tocco, pressione e gesti multipli
Il trascinamento non è l'unico gesto. pointerInput offre anche detectTapGestures per tocchi, doppi tocchi e pressioni prolungate, oltre a detectTransformGestures per lo zoom tramite pizzicamento e la rotazione.
Qui una pressione prolungata attiva una variazione di scala con una molla, combinando il rilevamento dei gesti con un Animatable.
@Composable
fun LongPressScale() {
val scale = remember { Animatable(1f) }
val scope = rememberCoroutineScope()
Box(
Modifier
.graphicsLayer { scaleX = scale.value; scaleY = scale.value }
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
scope.launch { scale.animateTo(1.4f, spring()) }
},
onPress = {
tryAwaitRelease()
scope.launch { scale.animateTo(1f, spring()) }
}
)
}
)
}Verifica rapida
Stai creando una scheda trascinabile che, al rilascio, dovrebbe rimbalzare tornando all'origine. Quale combinazione è la scelta idiomatica in Compose?
Riepilogo: gesti e molle
Ora è possibile creare movimenti naturali e interattivi:
Animatableoffre un controllo imperativo guidato da coroutine tramiteanimateTo/snapTo.springsi configura condampingRatio(rimbalzo) estiffness(velocità).pointerInput+detectDragGesturestrasformano il tocco in movimento;animateDecayaggiunge il lancio.anchoredDraggableporta l'elemento a posizioni fisse per le interazioni di swipe.rememberInfiniteTransitiongestisce effetti ripetuti come pulsazioni e shimmer.
Con questo si conclude la lezione sulle animazioni in Jetpack Compose: ora è possibile animare con sicurezza valori, visibilità, contenuti e gesti.
Domande Frequenti
La lezione «Animazioni con gesti e molle» è gratuita?
Sì — il testo completo di «Animazioni con gesti e molle» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Android Academy, passa a CoddyKit PRO. Il corso Android Academy include 4 lezioni in totale.
Cosa imparerò in «Animazioni con gesti e molle»?
Movimenti naturali basati sulla fisica Eserciti Android Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Android Academy?
Non è richiesta alcuna esperienza precedente. Android Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Animazioni con gesti e molle»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Android Academy?
Sì. Ogni lezione Android Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Perché le animazioni sono importanti
- Fondamenti di animate*AsState
- AnimatedVisibility e transizioni
- Animazioni con gesti e molle