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 die Animationsspezifikationen durch einen 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)
)

Es gibt verschiedene Arten von AnimationSpec, um verschiedene Animationstypen zu erstellen.

Mit spring physikbasierte Animationen erstellen

spring erstellt zwischen Start- und Endwerten eine physikbasierte Animation. Dafür sind zwei Parameter erforderlich: dampingRatio und stiffness.

dampingRatio definiert, wie schnell die Feder sein soll. Der Standardwert ist Spring.DampingRatioNoBouncy.

Abbildung 1: Verschiedene Federdämpfungsverhältnisse festlegen.

stiffness definiert, wie schnell sich die Feder in Richtung des Endwerts bewegen soll. Der Standardwert ist Spring.StiffnessMedium.

Abbildung 2: Unterschiedliche Federsteifheit einstellen

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

spring kann Unterbrechungen reibungsloser verarbeiten als dauerbasierte AnimationSpec-Typen, da dadurch die Kontinuität der Geschwindigkeit gewährleistet wird, wenn sich der Zielwert inmitten von Animationen ändert. 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 eine Berührung des Nutzers ausgelöst wird, und die Animation während des Fortschritts unterbrechen, sehen Sie, dass die Verwendung von tween nicht so reibungslos reagiert wie die Verwendung von spring.

Abbildung 3: Festlegen von tween vs. spring-Spezifikationen für Animationen und Unterbrechung der Animation.

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

tween animiert zwischen Start- und Endwerten über den angegebenen durationMillis mithilfe einer Easing-Kurve. tween ist die Abkürzung für das Wort dazwischen, da es zwischen zwei Werten steht.

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

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

Weitere Informationen finden Sie unter Easing.

Mit keyframes zu bestimmten Werten zu bestimmten Zeiten animieren

keyframes führt eine Animation basierend auf den Snapshot-Werten aus, die bei verschiedenen Zeitstempeln in der Animationsdauer angegeben wurden. Der Animationswert wird zwischen zwei Keyframe-Werten immer 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- bzw. Endwerte der Animation verwendet.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = keyframes {
        durationMillis = 375
        0.0f at 0 with LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 with FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.4f at 225 // ms
    }
)

Animation mit repeatable wiederholen

repeatable führt eine dauerbasierte Animation (z. B. tween oder keyframes) so lange aus, bis die angegebene Anzahl von Wiederholungen erreicht ist. Sie können den Parameter repeatMode übergeben, um anzugeben, ob die Animation wiederholt werden soll. Dabei wird am Anfang (RepeatMode.Restart) oder am Ende (RepeatMode.Reverse) begonnen.

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

Mit infiniteRepeatable unendlich eine Animation 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
    )
)

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 an Endwert andocken

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

Benutzerdefinierte Easing-Funktion festlegen

Bei dauerbasierten AnimationSpec-Vorgängen wie tween oder keyframes wird Easing verwendet, um den Anteil einer Animation anzupassen. So kann der Animationswert schneller und langsamer werden, anstatt sich mit einer konstanten 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 benutzerdefiniertes Easing kann wie im folgenden Code erstellt werden.

val CustomEasing = Easing { fraction -> fraction * fraction }

@Composable
fun EasingUsage() {
    val value by animateFloatAsState(
        targetValue = 1f,
        animationSpec = tween(
            durationMillis = 300,
            easing = CustomEasing
        )
    )
    // ……
}

Compose bietet mehrere integrierte Easing-Funktionen, die die meisten Anwendungsfälle abdecken. Unter Geschwindigkeit – Material Design finden Sie weitere Informationen dazu, welche Verwendungsmöglichkeiten Easing in Abhängigkeit von Ihrem Szenario ergeben.

  • 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 durch eine entsprechende TwoWayConverter in ein AnimationVector-Objekt und umgekehrt konvertiert, sodass das Animationskernsystem sie einheitlich verarbeiten kann. Ein Int wird beispielsweise als ein 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 ist im Wesentlichen eine Gruppe von vier Werten – Rot, Grün, Blau und Alpha. Daher wird Color in eine AnimationVector4D mit vier Gleitkommawerten umgewandelt. Auf diese Weise wird jeder in Animationen verwendete Datentyp je nach Dimensionalität entweder in AnimationVector1D, AnimationVector2D, AnimationVector3D oder AnimationVector4D konvertiert. Dadurch können verschiedene Komponenten des Objekts unabhängig voneinander animiert werden, jede mit ihrer eigenen Geschwindigkeitsverfolgung. Auf integrierte Converter für grundlegende Datentypen kann mit Convertern wie Color.VectorConverter oder Dp.VectorConverter zugegriffen werden.

Wenn Sie einen neuen Datentyp als Animationswert unterstützen möchten, können Sie eine eigene TwoWayConverter erstellen und der API zur Verfügung stellen. Sie können Ihren benutzerdefinierten Datentyp beispielsweise mit animateValueAsState 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)
            }
        )
    )
}

Die folgende Liste enthält einige integrierte VectorConverters: