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 legt fest, 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 tween nicht so reibungslos reagiert wie 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"
)

Animation mit repeatable wiederholen

repeatable führt eine laufzeitbasierte 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 AnimationSpec-Vorgängen, die auf der Dauer basieren (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 Kern-Animationssystem 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 Ihre 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: