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, um verschiedene Animationstypen zu erstellen.

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 Animations-APIs als standardmäßige AnimationSpec verwendet, z. B. animate*AsState und updateTransition.

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: Festlegen von tween vs. spring-Spezifikationen für Animationen und Unterbrechung der Animation.

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 Easing.

Mit keyframes zu bestimmten Werten zu bestimmten Zeiten 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.

Optional können die Werte bei 0 ms und zum Zeitpunkt der Dauer angegeben werden. 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 von Anfang (RepeatMode.Restart) oder von Ende (RepeatMode.Reverse) aus beginnt.

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 ist wie repeatable, wird aber für eine unbegrenzte Anzahl von Iterationen wiederholt.

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

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

Mit snap sofort zum Endwert springen

snap ist eine spezielle AnimationSpec, die 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 wie tween oder keyframes wird Easing verwendet, um den Anteil einer Animation anzupassen. So kann der animierte Wert beschleunigt und verlangsamt werden, anstatt sich mit konstanter Geschwindigkeit zu bewegen. Bruch ist ein Wert zwischen 0 (Start) und 1,0 (Ende), der den aktuellen Punkt in der Animation angibt.

Easing ist eigentlich eine Funktion, die einen Bruchwert zwischen 0 und 1,0 verwendet und eine Gleitkommazahl zurückgibt. Der zurückgegebene Wert kann außerhalb der Begrenzung liegen, um eine Über- oder Unterschreitung 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 durch Konvertierung in und aus AnimationVector animieren

Die meisten Compose-Animations-APIs unterstützen standardmäßig Float, Color, Dp und andere grundlegende Datentypen als Animationswerte. Manchmal müssen jedoch auch andere Datentypen animiert werden, auch Ihre benutzerdefinierten. Während der Animation wird jeder Animationswert 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: