Animationen anpassen

Viele der Animations-APIs akzeptieren in der Regel Parameter zur Anpassung ihres Verhaltens.

Animationen mit dem Parameter AnimationSpec anpassen

Mit den meisten Animations-APIs können Entwickler 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 zum Erstellen verschiedener Arten von Animationen.

Mit spring physikbasierte Animationen erstellen

spring erstellt eine physikbasierte Animation zwischen Start- und Endwerten. Er benötigt zwei Parameter: dampingRatio und stiffness.

dampingRatio definiert, wie federnd der Frühling sein soll. Der Standardwert ist Spring.DampingRatioNoBouncy.

Abbildung 1: Unterschiedliche Federdämpfverhältnisse einstellen.

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

Abbildung 2: Unterschiedliche Federsteifigkeit einstellen

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

spring kann Unterbrechungen reibungsloser handhaben als dauerbasierte AnimationSpec-Typen, da die Kontinuität der Geschwindigkeit garantiert wird, wenn sich der Zielwert in einer Animation ändert. spring wird von vielen Animations-APIs als Standard für AnimationSpec verwendet, z. B. von animate*AsState und updateTransition.

Wenn wir beispielsweise eine spring-Konfiguration auf die folgende durch Berührung des Nutzers gesteuerte Animation anwenden, können Sie beim Unterbrechen der Animation während des Fortschritts feststellen, dass die Verwendung von tween nicht so reibungslos reagiert wie die Verwendung von spring.

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

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

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

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 Zeiten zu bestimmten Werten animieren

keyframes wird basierend auf den Snapshot-Werten animiert, die zu verschiedenen Zeitstempeln während der Animationsdauer angegeben wurden. 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 Angabe der Werte bei 0 ms und zum Zeitpunkt der Dauer ist optional. Wenn Sie diese Werte nicht angeben, werden sie standardmäßig auf die Start- bzw. Endwerte der Animation gesetzt.

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 wiederholt eine dauerbasierte Animation wie tween oder keyframes aus, bis die angegebene Anzahl von Iterationen erreicht ist. Sie können den Parameter repeatMode übergeben, um festzulegen, ob die Animation wiederholt werden soll, indem Sie am Anfang (RepeatMode.Restart) oder vom Ende (RepeatMode.Reverse) beginnen.

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

Animation mit infiniteRepeatable endlos wiederholen

infiniteRepeatable ist wie repeatable, wiederholt sich jedoch für eine unendliche Anzahl von Iterationen.

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

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

Sofort zum Endwert mit snap andocken

snap ist eine spezielle AnimationSpec, die den Wert sofort auf den Endwert wechselt. 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. Dadurch wird der Animationswert beschleunigt und verlangsamt, anstatt sich mit einer konstanten Geschwindigkeit zu bewegen. Ein Bruch ist ein Wert zwischen 0 (Anfang) und 1,0 (Ende), der den aktuellen Punkt in der Animation angibt.

Das Easing ist im Grunde eine Funktion, die einen Bruchwert zwischen 0 und 1,0 annimmt 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 Easing-Funktionen für Ihr jeweiliges Szenario geeignet sind.

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

Benutzerdefinierte Datentypen durch Umwandlung 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 Sie jedoch andere Datentypen animieren, auch Ihre benutzerdefinierten. Während der Animation wird jeder animierte Wert als AnimationVector dargestellt. Der Wert wird in ein AnimationVector konvertiert und umgekehrt durch eine entsprechende TwoWayConverter, damit das Kernanimationssystem diese einheitlich verarbeiten kann. 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 ist im Wesentlichen ein Satz von vier Werten, nämlich Rot, Grün, Blau und Alpha. Daher wird Color in eine AnimationVector4D konvertiert, die vier Gleitkommawerte enthält. Auf diese Weise wird jeder in Animationen verwendete Datentyp je nach Dimensionalität entweder in AnimationVector1D, AnimationVector2D, AnimationVector3D oder AnimationVector4D konvertiert. So können verschiedene Komponenten des Objekts unabhängig voneinander animiert werden und jeweils eine eigene Geschwindigkeitsverfolgung haben. Auf integrierte Converter für grundlegende Datentypen kann mit Konvertierungen 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 an die API übergeben. So können Sie beispielsweise animateValueAsState verwenden, um Ihren benutzerdefinierten Datentyp so zu 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: