Android Academy · Lektion

Gest- och fjäderanimationer

Naturlig, fysikbaserad rörelse.

Lektion 4 av 413 steg

Gest- och fjäderanimationer är en gratis lektion i Android Academy på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Android Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Android Academy innehåller totalt 4 lektioner.

Interaktiv, fysisk rörelse

De mest tillfredsställande animationerna reagerar på användarens finger och känns som riktiga objekt, med rörelsemängd och studs. För att bygga sådana kombinerar ni gester med fysikbaserad animation.

Den här lektionen behandlar Animatable, fjädrar, fling-avklingning och hur de kopplas till draggester för ett naturligt och interaktivt användargränssnitt.

Animatable: kontroll på låg nivå

Medan animate*AsState reagerar på tillstånd ger Animatable er imperativ kontroll. Ni sparar ett sådant objekt i remember och styr det från en coroutine med anrop som animateTo eller snapTo.

Detta är grunden för geststyrd rörelse.

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

Fjädrar: dampingRatio och stiffness

En spring-specifikation definieras av två värden:

  • dampingRatio – hur studsande den är. Lägre värden ger mer studs; 1f (kritiskt dämpad) överskjuter inte målet.
  • stiffness – hur snabb den är. Högre värden når målet snabbare.

Compose tillhandahåller konstanter som Spring.DampingRatioMediumBouncy och Spring.StiffnessLow, så ni behöver sällan använda råa tal.

val spec = spring<Float>(
    dampingRatio = Spring.DampingRatioLowBouncy,
    stiffness = Spring.StiffnessMedium
)

// later, inside a coroutine:
// offset.animateTo(targetValue = 0f, animationSpec = spec)

Identifiera dragningar

För att göra rörelser interaktiva läser du av beröringsinmatning. Modifier.pointerInput med detectDragGestures rapporterar förflyttningen när användaren rör fingret.

Du ackumulerar förflyttningarna i en offset och tillämpar den på composable-funktionen.

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

Fjädrande återgång

Kombinera dragning med Animatable för en effekt där elementet "snäpper tillbaka". Under dragningen använder du snapTo för att omedelbart flytta elementet till fingrets position. När fingret släpps använder du animateTo(0f) med en fjäder, så att elementet studsar tillbaka till sin ursprungliga position.

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

Slunga med hastighet

En riktig slungning fortsätter efter att fingret lyfts. Spåra hastigheten med en VelocityTracker och skicka den sedan till animateDecay, så att elementet glider till ett naturligt stopp med hjälp av en friktionsbaserad DecayAnimationSpec.

val decay = rememberSplineBasedDecay<Float>()

// on drag end, with measured velocity:
// scope.launch {
//     offsetX.animateDecay(
//         initialVelocity = velocity,
//         animationSpec = decay
//     )
// }

Svep för att stänga med ankare

För svepgester med fasta vilopositioner, som svep för att stänga, snäpper anchoredDraggable till definierade ankare. Du deklarerar tillstånd och deras positioner i pixlar, så hanterar Compose fjäderrörelsen mellan dem.

enum class DragValue { Start, End }

val state = remember {
    AnchoredDraggableState(
        initialValue = DragValue.Start,
        anchors = DraggableAnchors {
            DragValue.Start at 0f
            DragValue.End at 300f
        }
    )
}

Oändliga och upprepade animationer

För kontinuerliga rörelser, som en pulserande punkt eller en laddningsanimation, använder du rememberInfiniteTransition med infiniteRepeatable. Ange RepeatMode som Reverse för att växla fram och tillbaka, eller Restart för att börja om från början i varje loop.

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

Kombinera gest och fjäder

Det typiska interaktiva mönstret är att dra för att flytta och släppa för att låta elementet lägga sig på plats. Spåra hastigheten under dragningen och använd sedan antingen animateDecay för att slunga elementet eller en spring för att lägga det mot ett ankare, beroende på avstånd eller hastighet.

Det är precis så här bottom sheets, karuseller och kort som kan stängas får sin naturliga känsla.

// pattern:
// 1) onDrag    -> animatable.snapTo(current + delta)
// 2) onDragEnd -> if (fast) animatable.animateDecay(velocity, decay)
//                 else      animatable.animateTo(nearestAnchor, spring())

Fjädrande positionering i ren Kotlin

För att känna hur en fjäder lägger sig på plats finns här en minimal loop i ren Kotlin. Den tillämpar en återställande kraft mot målet och dämpar hastigheten vid varje steg, enligt samma princip som Compose använder för varje bildruta.

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

Tryck, håll ned och flera gester

Dragning är inte den enda gesten. pointerInput erbjuder även detectTapGestures för tryck, dubbeltryck och långtryck, samt detectTransformGestures för nypzoomning och rotation.

Här utlöser ett långtryck en fjädrande skalning, där gestidentifiering kombineras med en 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()) }
                    }
                )
            }
    )
}

Snabbtest

Du bygger ett dragbart kort som ska studsa tillbaka till sin ursprungliga position när det släpps. Vilken kombination är det idiomatiska valet i Compose?

Sammanfattning: gester och fjädrar

Nu kan du skapa naturliga, interaktiva rörelser:

  • Animatable ger imperativ, koroutinstyrd kontroll via animateTo / snapTo.
  • spring justeras med dampingRatio (studsighet) och stiffness (hastighet).
  • pointerInput + detectDragGestures omvandlar beröring till rörelse; animateDecay lägger till slungning.
  • anchoredDraggable snäpper till fasta positioner för svepinteraktioner.
  • rememberInfiniteTransition driver loopande effekter som pulseringar och skimrande laddningsanimationer.

Det avslutar avsnittet om animationer i Jetpack Compose. Nu kan du med säkerhet animera värden, synlighet, innehåll och gester.

Gratis att börja

Lär dig Kotlin med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
36
Lektioner
152

Vanliga frågor

Är lektionen ”Gest- och fjäderanimationer” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Android Academy, inklusive ”Gest- och fjäderanimationer”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Android Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Gest- och fjäderanimationer”?

Naturlig, fysikbaserad rörelse. Ni övar på Android Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Android Academy?

Du behöver inga förkunskaper. Utbildningen i Android Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Gest- och fjäderanimationer”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Android Academy-lektionen?

Ja. Varje Android Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Varför animationer spelar roll
  2. Grunderna i animate*AsState
  3. AnimatedVisibility och övergångar
  4. Gest- och fjäderanimationer
← Tillbaka till Android Academy