Animationen anpassen

Viele der Animation APIs akzeptieren häufig Parameter zur Anpassung ihres Verhaltens.

Animationen mit dem Parameter AnimationSpec anpassen

Bei den meisten Animations-APIs können Entwickler Animationsspezifikationen mit einem optionalen AnimationSpec-Parameter anpassen.

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

Es gibt verschiedene Arten von AnimationSpec zum Erstellen verschiedener Arten von Animationen.

Physikbasierte Animationen mit spring erstellen

spring erstellt eine physikbasierte Animation zwischen Start- und Endwert. Es werden zwei Parameter benötigt: dampingRatio und stiffness.

dampingRatio gibt an, wie elastisch die Feder sein soll. Der Standardwert ist Spring.DampingRatioNoBouncy.

Abbildung 1: Sie können unterschiedliche Federdämpfungsverhältnisse festlegen.

stiffness definiert, wie schnell sich die Feder zum Endwert bewegen soll. Der Standardwert ist Spring.StiffnessMedium.

Abbildung 2: Andere Federsteifigkeit festlegen

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

spring kann Unterbrechungen besser verarbeiten als dauerbasierte AnimationSpec-Typen, da die Geschwindigkeit bei Änderungen des Zielwerts während der Animation konstant bleibt. spring wird von vielen Animation APIs wie animate*AsState und updateTransition als Standard-AnimationSpec verwendet.

Wenn wir beispielsweise eine spring-Konfiguration auf die folgende Animation anwenden, die durch Berührungen des Nutzers gesteuert wird, und die Animation während des Ablaufs unterbrechen, sehen wir, dass die Verwendung von tween nicht so reibungslos funktioniert wie die von spring.

Abbildung 3: tween- und spring-Spezifikationen für die Animation festlegen und sie unterbrechen

Mit tween zwischen Start- und Endwerten mit einer Ease-Kurve animieren

tween animiert zwischen Start- und Endwerten über den angegebenen durationMillis mit einer Ease-Kurve. tween ist eine Abkürzung für „between“ (zwischen), da der Wert zwischen zwei Werten liegt.

Sie können auch delayMillis angeben, um den Beginn der Animation zu verschieben.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing
    ),
    label = "tween delay"
)

Weitere Informationen finden Sie unter Übergangseffekte.

Mit keyframes bestimmte Werte zu bestimmten Zeitpunkten animieren

keyframes wird anhand der Snapshot-Werte animiert, die zu verschiedenen Zeitstempeln während der Dauer der Animation angegeben werden. Der Animationswert wird zu jedem Zeitpunkt zwischen zwei Keyframe-Werten interpoliert. Für jeden dieser keyframes kann „Easing“ angegeben werden, um die Interpolationskurve zu bestimmen.

Die Werte für 0 ms und für die Dauer sind optional. Wenn Sie diese Werte nicht angeben, werden standardmäßig die Start- und Endwerte der Animation verwendet.

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

Mit keyframesWithSplines zwischen Keyframes weich animieren

Wenn Sie eine Animation erstellen möchten, die beim Übergang zwischen Werten einer weichen Kurve folgt, können Sie keyframesWithSplines- statt keyframes-Animationsspezifikationen verwenden.

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

Splinebasierte ‑Keyframes sind besonders nützlich für die 2D-Bewegung von Elementen auf dem Bildschirm.

In den folgenden Videos werden die Unterschiede zwischen keyframes und keyframesWithSpline bei denselben X‑ und Y‑Koordinaten gezeigt, denen ein Kreis folgen sollte.

keyframes keyframesWithSplines

Wie Sie sehen, bieten die splinebasierten Keyframes glattere Übergänge zwischen den Punkten, da sie Bézierkurven verwenden, um die Übergänge zwischen den Elementen flüssig zu animieren. Diese Angabe ist für eine vordefinierte Animation nützlich. Wenn Sie jedoch mit von Nutzern gesteuerten Punkten arbeiten, sollten Sie lieber Federn verwenden, um eine ähnliche Glätte zwischen den Punkten zu erzielen, da diese unterbrochen werden können.

Animation mit repeatable wiederholen

repeatable führt eine dauerbasierte Animation (z. B. tween oder keyframes) wiederholt aus, bis die angegebene Anzahl von Iterationen erreicht ist. Mit dem Parameter repeatMode können Sie angeben, ob die Animation wiederholt werden soll, indem sie vom Anfang (RepeatMode.Restart) oder vom Ende (RepeatMode.Reverse) ausgeht.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = repeatable(
        iterations = 3,
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "repeatable spec"
)

Animation mit infiniteRepeatable unendlich wiederholen

infiniteRepeatable funktioniert ähnlich wie repeatable, wird aber unendlich oft wiederholt.

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

In Tests mit ComposeTestRule werden keine Animationen mit infiniteRepeatable ausgeführt. Die Komponente wird mit dem Anfangswert jedes animierten Werts gerendert.

Mit snap sofort zum Endwert springen

snap ist ein spezieller AnimationSpec, der den Wert sofort auf den Endwert umstellt. Sie können delayMillis angeben, um den Start der Animation zu verzögern.

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

Benutzerdefinierte Ease-Funktion festlegen

Bei dauerbasierten AnimationSpec-Vorgängen (z. B. tween oder keyframes) wird Easing verwendet, um den Bruchteil einer Animation anzupassen. So kann der animierte Wert beschleunigt und verlangsamt werden, anstatt sich mit konstanter Geschwindigkeit zu bewegen. „Fraction“ ist ein Wert zwischen 0 (Anfang) und 1,0 (Ende), der den aktuellen Punkt in der Animation angibt.

Die Funktion „Easing“ nimmt einen Bruchwert zwischen 0 und 1,0 an und gibt einen Gleitkommawert zurück. Der zurückgegebene Wert kann außerhalb des Grenzwerts liegen, um einen Über- oder Unterschuss darzustellen. Ein benutzerdefinierter Easing-Effekt kann wie im Code unten erstellt werden.

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 bietet mehrere integrierte Easing-Funktionen, die die meisten Anwendungsfälle abdecken. Weitere Informationen dazu, welche Art von Überblendung für Ihr Szenario geeignet ist, finden Sie unter Geschwindigkeit – Material Design.

  • FastOutSlowInEasing
  • LinearOutSlowInEasing
  • FastOutLinearEasing
  • LinearEasing
  • CubicBezierEasing
  • Mehr anzeigen

Benutzerdefinierte Datentypen animieren, indem sie in AnimationVector konvertiert werden

Die meisten Compose-Animations-APIs unterstützen standardmäßig Float, Color, Dp und andere grundlegende Datentypen als Animationswerte. Manchmal müssen Sie jedoch auch andere Datentypen animieren, einschließlich benutzerdefinierter. Während der Animation wird jeder animierte Wert als AnimationVector dargestellt. Der Wert wird von einem entsprechenden TwoWayConverter in einen AnimationVector und umgekehrt konvertiert, damit sie vom Kernanimationssystem einheitlich verarbeitet werden können. Ein Int wird beispielsweise als AnimationVector1D dargestellt, das einen einzelnen Gleitkommawert enthält. TwoWayConverter für Int sieht so aus:

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

Color besteht im Wesentlichen aus vier Werten: Rot, Grün, Blau und Alpha. Daher wird Color in eine AnimationVector4D umgewandelt, die vier Gleitkommawerte enthält. So wird jeder in Animationen verwendete Datentyp je nach Dimension in AnimationVector1D, AnimationVector2D, AnimationVector3D oder AnimationVector4D konvertiert. So können verschiedene Komponenten des Objekts unabhängig voneinander animiert werden, jede mit einer eigenen Geschwindigkeitsverfolgung. Auf integrierte Konvertierungstools für Basisdatentypen kann über Konvertierungstools wie Color.VectorConverter oder Dp.VectorConverter zugegriffen werden.

Wenn Sie die Unterstützung für einen neuen Datentyp als animierten Wert hinzufügen möchten, können Sie eine eigene TwoWayConverter erstellen und an die API übergeben. Mit animateValueAsState können Sie Ihren benutzerdefinierten Datentyp beispielsweise so animieren:

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

Die folgende Liste enthält einige vordefinierte VectorConverters: