Kurzanleitung zu Animationen in Compose

Compose verfügt über viele integrierte Animationsmechanismen und es kann schwierig sein, entscheiden Sie sich für eins. Nachfolgend finden Sie eine Liste mit gängigen Anwendungsfällen für Animationen. Für ausführlichere Informationen zu den verschiedenen verfügbaren API-Optionen finden Sie in der Dokumentation zum Erstellen von Animationen.

Gängige zusammensetzbare Eigenschaften animieren

Compose bietet praktische APIs, mit denen Sie viele gängige Animationsanwendungen. In diesem Abschnitt wird gezeigt, wie Sie gängige einer zusammensetzbaren Funktion.

Animieren eines Erscheinens / Verschwindens

<ph type="x-smartling-placeholder">
</ph> Grüne zusammensetzbare Funktion, die sich ein- und ausblenden lässt
Abbildung 1: Darstellung und Verschwinden eines Elements in einer Spalte animieren

Verwenden Sie AnimatedVisibility, um eine zusammensetzbare Funktion ein- oder auszublenden. Kinder drinnen AnimatedVisibility kann Modifier.animateEnterExit() für die eigene Eingabe verwenden oder den Übergang zu beenden.

var visible by remember {
    mutableStateOf(true)
}
// Animated visibility will eventually remove the item from the composition once the animation has finished.
AnimatedVisibility(visible) {
    // your composable here
    // ...
}

Mit den Eingabe- und Exit-Parametern von AnimatedVisibility können Sie konfigurieren, wie verhält sich eine zusammensetzbare Funktion, wenn sie erscheint und wieder verschwindet. Lesen Sie den vollständigen in der Dokumentation.

Sie können die Sichtbarkeit einer zusammensetzbaren Funktion auch animieren, Alpha im Zeitverlauf mit animateFloatAsState:

var visible by remember {
    mutableStateOf(true)
}
val animatedAlpha by animateFloatAsState(
    targetValue = if (visible) 1.0f else 0f,
    label = "alpha"
)
Box(
    modifier = Modifier
        .size(200.dp)
        .graphicsLayer {
            alpha = animatedAlpha
        }
        .clip(RoundedCornerShape(8.dp))
        .background(colorGreen)
        .align(Alignment.TopCenter)
) {
}

Die Änderung des Alpha-Werts bedeutet jedoch, dass die zusammensetzbare Funktion weiterhin in der Komposition und nimmt weiterhin den Platz ein, in dem es sich befindet. Dieses dazu führen, dass Screenreader und andere Bedienungshilfen das Element auf dem Bildschirm. AnimatedVisibility entfernt hingegen das Element aus der Komposition.

<ph type="x-smartling-placeholder">
</ph> Alpha einer zusammensetzbaren Funktion animieren
Abbildung 2: Alphaversion einer zusammensetzbaren Funktion animieren

Hintergrundfarbe animieren

<ph type="x-smartling-placeholder">
</ph> Zusammensetzbar, wobei sich die Hintergrundfarbe als Animation im Laufe der Zeit ändert, bei der die Farben übergangen werden
Abbildung 3: Hintergrundfarbe von zusammensetzbaren Funktionen animieren

val animatedColor by animateColorAsState(
    if (animateBackgroundColor) colorGreen else colorBlue,
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(animatedColor)
    }
) {
    // your composable here
}

Diese Option ist leistungsfähiger als die Verwendung von Modifier.background(). Modifier.background() ist für eine Farbeinstellung in Einzelaufnahme akzeptabel, aber wenn Animieren einer Farbe über einen bestimmten Zeitraum, kann dies zu mehr Neuzusammensetzungen notwendig ist.

Informationen zur unendlichen Animierung der Hintergrundfarbe finden Sie unter Animation wiederholen .

Größe einer zusammensetzbaren Funktion animieren

<ph type="x-smartling-placeholder">
</ph> Grüne zusammensetzbare Funktion, deren Größe animiert wird, ändert sich reibungslos.
Abbildung 4: Zusammensetzbare Animation zwischen einer kleinen und einer größeren Größe

Mit „Compose“ können Sie die Größe von zusammensetzbaren Funktionen auf verschiedene Arten animieren. Verwenden Sie animateContentSize() für Animationen zwischen zusammensetzbaren Größenänderungen

Wenn Sie beispielsweise ein Textfeld haben, das Text enthält, der sich von einem zu Mehrere Linien können Sie Modifier.animateContentSize() verwenden, um eine gleichmäßigere Übergang:

var expanded by remember { mutableStateOf(false) }
Box(
    modifier = Modifier
        .background(colorBlue)
        .animateContentSize()
        .height(if (expanded) 400.dp else 200.dp)
        .fillMaxWidth()
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            expanded = !expanded
        }

) {
}

Sie können auch AnimatedContent mit einem SizeTransform verwenden, um wie Größenänderungen erfolgen sollen.

Position der zusammensetzbaren Funktion animieren

<ph type="x-smartling-placeholder">
</ph> Grüne, zusammensetzbare Funktion mit sanfter Animation nach unten und rechts
Abbildung 5: Zusammensetzbares Verschieben durch einen Offset

Um die Position einer zusammensetzbaren Funktion zu animieren, verwenden Sie Modifier.offset{ } in Kombination mit animateIntOffsetAsState().

var moved by remember { mutableStateOf(false) }
val pxToMove = with(LocalDensity.current) {
    100.dp.toPx().roundToInt()
}
val offset by animateIntOffsetAsState(
    targetValue = if (moved) {
        IntOffset(pxToMove, pxToMove)
    } else {
        IntOffset.Zero
    },
    label = "offset"
)

Box(
    modifier = Modifier
        .offset {
            offset
        }
        .background(colorBlue)
        .size(100.dp)
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            moved = !moved
        }
)

Wenn Sie sicherstellen möchten, dass zusammensetzbare Funktionen nicht über oder unter anderen zusammensetzbare Funktionen verwenden, wenn Sie für die Animation von Position oder Größe Modifier.layout{ } verwenden. Dieses gibt Änderungen der Größe und Position an das übergeordnete Element weiter, was sich auf Kinder.

Wenn Sie z. B. ein Box innerhalb einer Column und die anderen untergeordneten Elemente verschieben, verschieben müssen, wenn Box bewegt wird, fügen Sie die Versatzinformationen mit Modifier.layout{ } so:

var toggled by remember {
    mutableStateOf(false)
}
val interactionSource = remember {
    MutableInteractionSource()
}
Column(
    modifier = Modifier
        .padding(16.dp)
        .fillMaxSize()
        .clickable(indication = null, interactionSource = interactionSource) {
            toggled = !toggled
        }
) {
    val offsetTarget = if (toggled) {
        IntOffset(150, 150)
    } else {
        IntOffset.Zero
    }
    val offset = animateIntOffsetAsState(
        targetValue = offsetTarget, label = "offset"
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
    Box(
        modifier = Modifier
            .layout { measurable, constraints ->
                val offsetValue = if (isLookingAhead) offsetTarget else offset.value
                val placeable = measurable.measure(constraints)
                layout(placeable.width + offsetValue.x, placeable.height + offsetValue.y) {
                    placeable.placeRelative(offsetValue)
                }
            }
            .size(100.dp)
            .background(colorGreen)
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
}

<ph type="x-smartling-placeholder">
</ph> Zwei Boxen,wobei die zweite Box ihre X- und Y-Position animiert. Die dritte Box reagiert, indem sie sich ebenfalls um den Y-Wert bewegt.
Abbildung 6: Animation mit Modifier.layout{ }

Padding einer zusammensetzbaren Funktion animieren

<ph type="x-smartling-placeholder">
</ph> Die grüne zusammensetzbare Funktion wird durch einen Klick kleiner und größer und die Abstände sind animiert.
Abbildung 7: Kombinierbar mit animierten Padding-Werten

Um den Abstand einer zusammensetzbaren Funktion zu animieren, verwenden Sie animateDpAsState in Kombination mit Modifier.padding():

var toggled by remember {
    mutableStateOf(false)
}
val animatedPadding by animateDpAsState(
    if (toggled) {
        0.dp
    } else {
        20.dp
    },
    label = "padding"
)
Box(
    modifier = Modifier
        .aspectRatio(1f)
        .fillMaxSize()
        .padding(animatedPadding)
        .background(Color(0xff53D9A1))
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            toggled = !toggled
        }
)

Höhe einer zusammensetzbaren Funktion animieren

<ph type="x-smartling-placeholder">
Abbildung 8. Die Höhenanimation von zusammensetzbaren Funktionen wird beim Klicken animiert.

Um die Höhe einer zusammensetzbaren Funktion zu animieren, verwenden Sie animateDpAsState in Kombination mit Modifier.graphicsLayer{ }. Für einmalige Höhenänderungen verwenden Sie Modifier.shadow() Wenn Sie den Schatten animieren, verwenden Sie Der Modifier.graphicsLayer{ }-Modifikator ist die leistungsstärkere Option.

val mutableInteractionSource = remember {
    MutableInteractionSource()
}
val pressed = mutableInteractionSource.collectIsPressedAsState()
val elevation = animateDpAsState(
    targetValue = if (pressed.value) {
        32.dp
    } else {
        8.dp
    },
    label = "elevation"
)
Box(
    modifier = Modifier
        .size(100.dp)
        .align(Alignment.Center)
        .graphicsLayer {
            this.shadowElevation = elevation.value.toPx()
        }
        .clickable(interactionSource = mutableInteractionSource, indication = null) {
        }
        .background(colorGreen)
) {
}

Alternativ können Sie die zusammensetzbare Funktion Card verwenden und die Höheneigenschaft auf für die einzelnen Bundesstaaten.

Textskalierung, -übersetzung oder -drehung animieren

<ph type="x-smartling-placeholder">
</ph> Zusammensetzbarer Text mit Text
Abbildung 9: Text wird nahtlos zwischen zwei Größen animiert.

Legen Sie beim Animieren der Skalierung, Verschiebung oder Drehung von Text den textMotion fest. auf TextStyle auf TextMotion.Animated gesetzt. So sorgen Sie für eine Textanimationen zu wechseln. Verwenden Sie Modifier.graphicsLayer{ } für Folgendes: übersetzen, drehen oder skalieren.

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val scale by infiniteTransition.animateFloat(
    initialValue = 1f,
    targetValue = 8f,
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "scale"
)
Box(modifier = Modifier.fillMaxSize()) {
    Text(
        text = "Hello",
        modifier = Modifier
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                transformOrigin = TransformOrigin.Center
            }
            .align(Alignment.Center),
        // Text composable does not take TextMotion as a parameter.
        // Provide it via style argument but make sure that we are copying from current theme
        style = LocalTextStyle.current.copy(textMotion = TextMotion.Animated)
    )
}

Textfarbe animieren

<ph type="x-smartling-placeholder">
</ph> Der Text
Abbildung 10. Beispiel für die Animation der Textfarbe

Um die Textfarbe zu animieren, verwende die Lambda-Funktion color in der zusammensetzbaren Funktion BasicText:

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val animatedColor by infiniteTransition.animateColor(
    initialValue = Color(0xFF60DDAD),
    targetValue = Color(0xFF4285F4),
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "color"
)

BasicText(
    text = "Hello Compose",
    color = {
        animatedColor
    },
    // ...
)

Zwischen verschiedenen Inhaltstypen wechseln

<ph type="x-smartling-placeholder">
</ph> Greenscreen mit Text
Abbildung 11. Änderungen zwischen verschiedenen zusammensetzbaren Funktionen mit animateContent animieren (verlangsamt)

Verwenden Sie AnimatedContent für Animationen zwischen verschiedenen zusammensetzbaren Funktionen, Standardfade zwischen zusammensetzbaren Funktionen verwenden möchten, verwenden Sie Crossfade.

var state by remember {
    mutableStateOf(UiState.Loading)
}
AnimatedContent(
    state,
    transitionSpec = {
        fadeIn(
            animationSpec = tween(3000)
        ) togetherWith fadeOut(animationSpec = tween(3000))
    },
    modifier = Modifier.clickable(
        interactionSource = remember { MutableInteractionSource() },
        indication = null
    ) {
        state = when (state) {
            UiState.Loading -> UiState.Loaded
            UiState.Loaded -> UiState.Error
            UiState.Error -> UiState.Loading
        }
    },
    label = "Animated Content"
) { targetState ->
    when (targetState) {
        UiState.Loading -> {
            LoadingScreen()
        }
        UiState.Loaded -> {
            LoadedScreen()
        }
        UiState.Error -> {
            ErrorScreen()
        }
    }
}

AnimatedContent kann so angepasst werden, dass viele unterschiedliche Arten von Eingaben und Exit-Übergänge. Weitere Informationen finden Sie in der Dokumentation zu AnimatedContent oder lesen Sie diesen Blogpost auf AnimatedContent

Animiere zu verschiedenen Zielen

<ph type="x-smartling-placeholder">
</ph> Zwei zusammensetzbare Elemente, eine mit der Aufschrift „Landing“ und eine blaue „Detail“
Abbildung 12. Animieren von zusammensetzbaren Funktionen mit „navigation-compose“

Um Übergänge zwischen zusammensetzbaren Funktionen zu animieren, wenn Sie die navigation-compose verwenden, geben Sie enterTransition und exitTransition für eine zusammensetzbare Funktion. Sie können die Standardanimation auch wird für alle Ziele auf der obersten Ebene NavHost verwendet:

val navController = rememberNavController()
NavHost(
    navController = navController, startDestination = "landing",
    enterTransition = { EnterTransition.None },
    exitTransition = { ExitTransition.None }
) {
    composable("landing") {
        ScreenLanding(
            // ...
        )
    }
    composable(
        "detail/{photoUrl}",
        arguments = listOf(navArgument("photoUrl") { type = NavType.StringType }),
        enterTransition = {
            fadeIn(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideIntoContainer(
                animationSpec = tween(300, easing = EaseIn),
                towards = AnimatedContentTransitionScope.SlideDirection.Start
            )
        },
        exitTransition = {
            fadeOut(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideOutOfContainer(
                animationSpec = tween(300, easing = EaseOut),
                towards = AnimatedContentTransitionScope.SlideDirection.End
            )
        }
    ) { backStackEntry ->
        ScreenDetails(
            // ...
        )
    }
}

Es gibt viele verschiedene Arten von Wechsel zwischen Ein- und Ausblenden. unterschiedliche Auswirkungen auf eingehende und ausgehende Inhalte haben, siehe Dokumentation.

Animation wiederholen

<ph type="x-smartling-placeholder">
</ph> Ein grüner Hintergrund, der sich durch Animieren der beiden Farben in einen blauen Hintergrund verwandelt.
Abbildung 13. Animation der Hintergrundfarbe zwischen zwei Werten, unendlich

rememberInfiniteTransition mit einem infiniteRepeatable verwenden animationSpec, um die Animation fortlaufend zu wiederholen. RepeatModes ändern zu wie er hin und her wechseln soll.

Mit finiteRepeatable können Sie eine bestimmte Anzahl von Wiederholungen festlegen.

val infiniteTransition = rememberInfiniteTransition(label = "infinite")
val color by infiniteTransition.animateColor(
    initialValue = Color.Green,
    targetValue = Color.Blue,
    animationSpec = infiniteRepeatable(
        animation = tween(1000, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ),
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(color)
    }
) {
    // your composable here
}

Animation beim Start einer zusammensetzbaren Funktion starten

LaunchedEffect wird ausgeführt, wenn eine zusammensetzbare Funktion in die Zusammensetzung aufgenommen wird. Los gehts eine Animation beim Start einer zusammensetzbaren Funktion. Statusänderung. Animatable mit der Methode animateTo zum Starten von Animation beim Start:

val alphaAnimation = remember {
    Animatable(0f)
}
LaunchedEffect(Unit) {
    alphaAnimation.animateTo(1f)
}
Box(
    modifier = Modifier.graphicsLayer {
        alpha = alphaAnimation.value
    }
)

Sequenzielle Animationen erstellen

<ph type="x-smartling-placeholder">
</ph> Vier Kreise mit grünen Pfeilen, die nacheinander animiert werden
Abbildung 14. Diagramm, das den Ablauf einer sequenziellen Animation zeigt.

Verwenden Sie die Animatable-Koroutinen-APIs für sequenzielle oder gleichzeitige Ausführung Animationen. Aufrufen von animateTo für Animatable nach den anderen Ursachen jede Animation wird erst beendet, wenn die vorherigen Animationen beendet sind, bevor Sie fortfahren . Der Grund hierfür ist, dass es sich um eine Sperren-Funktion handelt.

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    alphaAnimation.animateTo(1f)
    yAnimation.animateTo(100f)
    yAnimation.animateTo(500f, animationSpec = tween(100))
}

Gleichzeitige Animationen erstellen

<ph type="x-smartling-placeholder">
</ph> Drei Kreise mit grünen Pfeilen, die jeweils als Animation dienen und alle gleichzeitig animieren
Abbildung 15. Diagramm, das den Fortschritt gleichzeitiger Animationen zeigt.

Verwenden Sie die Koroutine-APIs (Animatable#animateTo() oder animate) oder die Transition API verwenden, um gleichzeitige Animationen zu erstellen. Wenn Sie mehrere Funktionen im Kontext einer Koroutine starten, starten sie die Animationen im gleichen Zeit:

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    launch {
        alphaAnimation.animateTo(1f)
    }
    launch {
        yAnimation.animateTo(100f)
    }
}

Mit der updateTransition API können Sie denselben Status für verschiedene Eigenschaftenanimationen gleichzeitig erstellen. Im Beispiel unten wird eine Animation Zwei Eigenschaften, die durch eine Statusänderung gesteuert werden, rect und borderWidth:

var currentState by remember { mutableStateOf(BoxState.Collapsed) }
val transition = updateTransition(currentState, label = "transition")

val rect by transition.animateRect(label = "rect") { state ->
    when (state) {
        BoxState.Collapsed -> Rect(0f, 0f, 100f, 100f)
        BoxState.Expanded -> Rect(100f, 100f, 300f, 300f)
    }
}
val borderWidth by transition.animateDp(label = "borderWidth") { state ->
    when (state) {
        BoxState.Collapsed -> 1.dp
        BoxState.Expanded -> 0.dp
    }
}

Animationsleistung optimieren

Animationen in „Compose“ können zu Leistungsproblemen führen. Dies liegt an der Natur des Animation: schnelles Verschieben oder Ändern von Pixeln auf dem Bildschirm, Frame für Frame, um die Illusion von Bewegung zu erzeugen.

Sehen Sie sich die verschiedenen Phasen des Schreibens an: Komposition, Layout und Zeichnen. Wenn die Layoutphase verändert, müssen alle betroffenen zusammensetzbaren Layout neu gestalten und neu zeichnen. Wenn Ihre Animation in der Zeichenphase stattfindet, standardmäßig leistungsfähiger sein, als wenn Sie die Animation im Layout ausführen, da es insgesamt weniger Arbeit hätte.

Wähle Lambda aus, damit deine App während der Animation möglichst wenig tut Version von Modifier. Dabei wird die Neuzusammensetzung übersprungen und außerhalb der Kompositionsphase zu erstellen. Andernfalls verwenden Sie Modifier.graphicsLayer{ }, da dieser Modifikator immer in der Zeichnung ausgeführt wird . Weitere Informationen hierzu finden Sie im Abschnitt Lesevorgänge aussetzen in Leistungsdokumentation.

Timing der Animation ändern

Beim Schreiben werden standardmäßig Frühlingsanimationen verwendet. Federn oder physikbasierten Animationen natürlicher wirken. Sie sind auch unterbrechbar, sie berücksichtigen die aktuelle Geschwindigkeit des Objekts anstelle einer festen Zeit. Wenn Sie die Standardeinstellung überschreiben möchten, können Sie alle oben gezeigten Animations-APIs können eine animationSpec festlegen, um die Ausführung einer Animation anzupassen, ob sie über eine bestimmte Dauer ausgeführt werden oder hüpfender sein soll.

Im Folgenden finden Sie eine Zusammenfassung der verschiedenen animationSpec-Optionen:

  • spring: Physikbasierte Animationen, die Standardeinstellung für alle Animationen. Ich kann das Steifheits- oder Dämpfungsverhältnis ändern, um eine andere Animation zu erzielen. Design.
  • tween (kurz für zwischen): Animationsdauer nach Dauer, animiert mit der Funktion Easing zwischen zwei Werten.
  • keyframes: Spezifikation für die Angabe von Werten an bestimmten wichtigen Punkten in einer Animation.
  • repeatable: Dauerbasierte Spezifikation, die eine bestimmte Anzahl von Ausführungen hat, durch RepeatMode angegeben.
  • infiniteRepeatable: Dauerbasierte Spezifikation, die unbegrenzt gültig ist.
  • snap: Andockt sofort und ohne Animation an den Endwert.
<ph type="x-smartling-placeholder">
</ph> Alt-Text hier eingeben
Abbildung 16. Kein Spezifikationssatz im Vergleich zu benutzerdefiniertem Spring-Spezifikationssatz

Weitere Informationen zu animationSpecs finden Sie in der vollständigen Dokumentation.

Weitere Informationen

Weitere Beispiele für lustige Animationen in „Schreiben“ finden Sie hier: