Animationen anpassen

Viele der Animations-APIs akzeptieren Parameter, mit denen ihr Verhalten angepasst werden kann.

Animationen mit dem Parameter AnimationSpec anpassen

Bei den meisten Animations-APIs können Entwickler die 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 unterschiedliche Arten von Animationen zu erstellen.

Physikbasierte Animation mit spring erstellen

spring erstellt eine physikbasierte Animation zwischen Start- und Endwerten. Sie verwendet zwei Parameter: dampingRatio und stiffness.

dampingRatio definiert, wie stark die Feder federn soll. Der Standardwert ist Spring.DampingRatioNoBouncy.

Abbildung 1: Unterschiedliche Federdämpfungsverhältnisse festlegen

stiffness definiert, wie schnell sich die Feder zum 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
    ),
    label = "spring spec"
)

spring kann Unterbrechungen besser verarbeiten als dauerbasierte AnimationSpec-Typen, da die Kontinuität der Geschwindigkeit gewährleistet ist, wenn sich der Zielwert während der Animationen ändert. 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ührung des Nutzers gesteuert wird, können Sie sehen, dass die Animation bei Verwendung von tween nicht so flüssig reagiert wie bei Verwendung von spring, wenn sie während des Fortschritts unterbrochen wird.

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

Animation zwischen Start- und Endwerten mit einer Easing-Kurve mit tween

tween animiert zwischen Start- und Endwerten über die angegebene durationMillis mithilfe einer Easing-Kurve. tween ist die Abkürzung für „between“ (zwischen), da es zwischen zwei Werten liegt.

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

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

keyframes wird basierend auf den Snapshot-Werten animiert, die zu verschiedenen Zeitstempeln während der Animation angegeben sind. Zu jedem Zeitpunkt wird der Animationswert zwischen zwei Keyframe-Werten interpoliert. Für jeden dieser Keyframes kann ein Easing angegeben werden, um die Interpolationskurve zu bestimmen.

Die Angabe der Werte bei 0 ms und bei der Dauer ist 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 kannst du flüssige Animationen zwischen Keyframes erstellen

Wenn Sie eine Animation erstellen möchten, die beim Übergang zwischen Werten einer glatten Kurve folgt, können Sie keyframesWithSplines anstelle von 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
    }
)

Spline-basierte 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 anhand derselben x- und y-Koordinaten gezeigt, denen ein Kreis folgen soll.

keyframes keyframesWithSplines

Wie Sie sehen, bieten die Spline-basierten Keyframes flüssigere Übergänge zwischen den Punkten, da sie Bezier-Kurven verwenden, um flüssige Animationen zwischen den Elementen zu erstellen. Diese Spezifikation ist für eine voreingestellte Animation nützlich. Wenn Sie jedoch mit nutzergesteuerten Punkten arbeiten, ist es besser, Federn zu verwenden, um eine ähnliche Glätte zwischen den Punkten zu erreichen, da diese unterbrochen werden können.

Animation mit repeatable wiederholen

repeatable führt eine zeitbasierte 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 von vorn (RepeatMode.Restart) oder von hinten (RepeatMode.Reverse) wiederholt werden soll.

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 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 Animationen mit infiniteRepeatable nicht 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 umschaltet. 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 Easing-Funktion festlegen

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

Easing ist eine Funktion, die einen Bruchwert zwischen 0 und 1,0 annimmt und einen Gleitkommawert zurückgibt. Der zurückgegebene Wert kann außerhalb der Grenze liegen, um ein Über- oder Unterschreiten 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
        ),
        label = "custom easing"
    )
    // ……
}

Compose bietet mehrere integrierte Easing-Funktionen, die die meisten Anwendungsfälle abdecken. Weitere Informationen dazu, welche Beschleunigungskurve Sie je nach Szenario verwenden sollten, finden Sie unter Speed – Material Design.

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

Benutzerdefinierte Datentypen durch Konvertieren in und aus AnimationVector animieren

Die meisten Compose Animation APIs unterstützen standardmäßig Float, Color, Dp und andere grundlegende Datentypen als Animationswerte. Manchmal müssen Sie jedoch andere Datentypen animieren, einschließlich Ihrer benutzerdefinierten Datentypen. Während der Animation wird jeder animierte Wert als AnimationVector dargestellt. Der Wert wird von einem entsprechenden TwoWayConverter in ein AnimationVector-Objekt konvertiert und umgekehrt, damit das Core Animation-System sie einheitlich verarbeiten kann. Beispiel: Ein Int wird 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: Rot, Grün, Blau und Alpha. Daher wird Color in ein AnimationVector4D mit vier Gleitkommawerten konvertiert. Auf diese Weise wird jeder in Animationen verwendete Datentyp je nach Dimensionalität in AnimationVector1D, AnimationVector2D, AnimationVector3D oder AnimationVector4D konvertiert. So können verschiedene Komponenten des Objekts unabhängig voneinander animiert werden, jeweils mit eigener Geschwindigkeitserfassung. Auf integrierte Konverter für grundlegende Datentypen kann mit Konvertern wie Color.VectorConverter oder Dp.VectorConverter zugegriffen werden.

Wenn du Unterstützung für einen neuen Datentyp als animierten Wert hinzufügen möchtest, kannst du einen eigenen TwoWayConverter erstellen und der API zur Verfügung stellen. Sie können 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)
            }
        ),
        label = "size"
    )
}

Die folgende Liste enthält einige integrierte VectorConverters: