0Pricing
Android Academy · Lektion

Gesten- und Spring-Animationen

Natürliche, physikbasierte Bewegung

Gesten- und Spring-Animationen ist eine kostenlose Android Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Android Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Android Academy-Kurs umfasst insgesamt 4 Lektionen.

Interaktive, physische Bewegung

Die ansprechendsten Animationen reagieren auf den Finger des Nutzers und fühlen sich wie echte Objekte an – mit Schwung und Nachfedern. Dafür kombinieren Sie Gesten mit physikbasierter Animation.

In dieser Lektion geht es um Animatable, Springs, Fling-Dämpfung und deren Verbindung mit Ziehgesten für eine natürliche, interaktive UI.

Animatable: Steuerung auf niedriger Ebene

Während animate*AsState auf Zustandsänderungen reagiert, bietet Animatable Ihnen imperative Kontrolle. Sie speichern ein Objekt davon mit remember und steuern es aus einer Coroutine heraus mit Aufrufen wie animateTo oder snapTo.

Das bildet die Grundlage für gestengesteuerte Bewegung.

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

Springs: dampingRatio und stiffness

Eine spring-Spezifikation wird durch zwei Werte definiert:

  • dampingRatio – wie stark das Element schwingt. Ein niedrigerer Wert erzeugt mehr Schwingung; 1f (kritische Dämpfung) verhindert ein Überschwingen.
  • stiffness – wie schnell die Bewegung ist. Ein höherer Wert erreicht das Ziel schneller.

Compose stellt Konstanten wie Spring.DampingRatioMediumBouncy und Spring.StiffnessLow bereit, sodass Sie nur selten Rohwerte benötigen.

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

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

Ziehgesten erkennen

Damit Bewegungen interaktiv werden, lesen Sie die Touch-Eingaben aus. Modifier.pointerInput mit detectDragGestures meldet die Verschiebungen beim Ziehen, während der Benutzer seinen Finger bewegt.

Sie addieren diese Verschiebungen zu einem Offset und wenden ihn auf das Composable an.

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

Mit einer Feder zurückschnappen

Kombinieren Sie das Ziehen mit Animatable, um einen „Zurückschnapp“-Effekt zu erzeugen. Während des Ziehens setzen Sie die Fingerposition mit snapTo sofort; beim Loslassen verwenden Sie animateTo(0f) mit einer Feder, sodass das Element an seine Ausgangsposition zurückfedert.

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

Mit Geschwindigkeit schleudern

Bei echten Schleuderbewegungen bewegt sich das Element weiter, nachdem der Finger abgehoben wurde. Erfassen Sie die Geschwindigkeit mit einem VelocityTracker und übergeben Sie sie anschließend an animateDecay, damit das Element mithilfe einer reibungsbasierten DecayAnimationSpec natürlich ausläuft.

val decay = rememberSplineBasedDecay<Float>()

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

Wischen zum Schließen mit Ankern

Bei Wischgesten mit festgelegten Ruhepositionen, etwa beim Wischen zum Schließen, rastet anchoredDraggable an definierten Ankern ein. Sie deklarieren die Zustände und ihre Positionen in Pixeln, und Compose übernimmt die Federbewegung zwischen ihnen.

enum class DragValue { Start, End }

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

Endlose und wiederholte Animationen

Für kontinuierliche Bewegungen wie einen pulsierenden Punkt oder einen Lade-Schimmer verwenden Sie rememberInfiniteTransition mit infiniteRepeatable. Setzen Sie RepeatMode auf Reverse, um eine Hin-und-her-Bewegung zu erzeugen, oder auf Restart, um die Animation in einer Schleife neu zu starten.

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

Geste und Feder kombinieren

Das typische interaktive Muster lautet: ziehen, um zu bewegen, und loslassen, um einzurasten. Erfassen Sie während des Ziehens die Geschwindigkeit und schleudern Sie das Element anschließend entweder mit animateDecay oder lassen Sie es abhängig von Entfernung oder Geschwindigkeit mit einer spring zu einem Anker zurückkehren.

Genau so fühlen sich Bottom Sheets, Karussells und Karten zum Wegwischen so natürlich an.

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

Einrasten mit einer Feder in reinem Kotlin

Um zu verstehen, wie eine Feder zur Ruhe kommt, sehen Sie hier eine minimale Schleife in reinem Kotlin. Sie wendet in jedem Schritt eine Rückstellkraft auf das Ziel an und dämpft die Geschwindigkeit – nach demselben Prinzip, das Compose in jedem Frame ausführt.

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

Tippen, Drücken und mehrere Gesten

Ziehen ist nicht die einzige Geste. pointerInput bietet auch detectTapGestures für einfaches Tippen, Doppeltippen und langes Drücken sowie detectTransformGestures für Pinch-to-Zoom und Drehungen.

Hier löst ein langes Drücken eine Federskalierung aus, wobei die Gestenerkennung mit einem Animatable kombiniert wird.

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

Kurzer Test

Sie erstellen eine verschiebbare Karte, die beim Loslassen zu ihrem Ursprung zurückfedern soll. Welche Kombination entspricht der idiomatischen Lösung in Compose?

Zusammenfassung: Gesten und Federn

Sie können jetzt natürliche, interaktive Bewegungen erstellen:

  • Animatable ermöglicht eine imperative, coroutine-gesteuerte Steuerung über animateTo und snapTo.
  • spring wird mit dampingRatio (Federn) und stiffness (Geschwindigkeit) abgestimmt.
  • pointerInput und detectDragGestures machen aus Touch-Eingaben Bewegungen; animateDecay ergänzt Schleuderbewegungen.
  • anchoredDraggable rastet bei Wischinteraktionen an festen Positionen ein.
  • rememberInfiniteTransition steuert Schleifeneffekte wie Pulsieren und Schimmern.

Damit ist das Kapitel „Animationen in Jetpack Compose“ abgeschlossen. Sie können jetzt Werte, Sichtbarkeit, Inhalte und Gesten sicher animieren.

Häufig gestellte Fragen

Ist die Lektion „Gesten- und Spring-Animationen“ kostenlos?

Ja — der vollständige Text von „Gesten- und Spring-Animationen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Android Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Android Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Gesten- und Spring-Animationen“?

Natürliche, physikbasierte Bewegung Du übst Android Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Android Academy zu starten?

Keine Vorkenntnisse erforderlich. Android Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Gesten- und Spring-Animationen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Android Academy-Lektion Code schreiben und ausführen?

Ja. Jede Android Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Warum Animationen wichtig sind
  2. Grundlagen von animate*AsState
  3. AnimatedVisibility und Transitions
  4. Gesten- und Spring-Animationen
← Zurück zu Android Academy