Compose verfügt über viele integrierte Animationsmechanismen und es kann schwierig sein, entscheiden Sie sich für eins. Im Folgenden finden Sie eine Liste gängiger Anwendungsfälle für Animationen. Weitere Informationen zu den verschiedenen verfügbaren API-Optionen findest du in der vollständigen Dokumentation zur Erstellung von Animationen.
Gängige zusammensetzbare Eigenschaften animieren
Compose bietet praktische APIs, mit denen sich viele gängige Anwendungsfälle für Animationen lösen lassen. In diesem Abschnitt wird gezeigt, wie Sie gängige einer zusammensetzbaren Funktion.
Animieren eines Erscheinens / Verschwindens
Verwende AnimatedVisibility
, um eine zusammensetzbare Funktion ein- oder auszublenden. Untergeordnete Elemente von AnimatedVisibility
können Modifier.animateEnterExit()
für ihren eigenen Eintritts- oder Ausstiegsübergang verwenden.
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
wie sich eine zusammensetzbare Funktion verhält,
wenn sie erscheint und wieder verschwindet. Weitere Informationen finden Sie in der vollständigen Dokumentation.
Eine weitere Möglichkeit, die Sichtbarkeit eines Composeables zu animieren, besteht darin, den Alphawert mit animateFloatAsState
im Zeitverlauf zu animieren:
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 bestehend aus
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. Mit AnimatedVisibility
wird das Element dagegen irgendwann aus der Komposition entfernt.
Hintergrundfarbe 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 einmalige Farbeinstellung akzeptabel, aber wenn eine Farbe im Zeitverlauf animiert wird, kann dies zu mehr Neuzusammensetzungen als nötig führen.
Informationen zur unendlichen Animierung der Hintergrundfarbe finden Sie unter Animation wiederholen .
Größe eines Composeables animieren
In Compose können Sie die Größe von Composeables auf verschiedene Arten animieren. Verwenden Sie animateContentSize()
für Animationen zwischen Größenänderungen von Kompositionen.
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 zu beschreiben, wie Größenänderungen erfolgen sollen.
Position der zusammensetzbaren Funktion animieren
Wenn Sie die Position eines Composeables animieren möchten, 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. Dieser Modifikator überträgt Größe und Position an das übergeordnete Element, was sich dann auf andere untergeordnete Elemente auswirkt.
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) ) }
Padding einer zusammensetzbaren Funktion animieren
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
Um die Höhe einer zusammensetzbaren Funktion zu animieren, verwenden Sie animateDpAsState
in Kombination mit
Modifier.graphicsLayer{ }
. Verwenden Sie für einmalige Höhenänderungen Modifier.shadow()
. Wenn Sie den Schatten animieren, ist die Verwendung des Modifier.graphicsLayer{ }
-Modifikators 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.
Text skalieren, verschieben oder drehen
Legen Sie beim Animieren der Skalierung, Verschiebung oder Drehung von Text den textMotion
fest.
auf TextStyle
auf TextMotion.Animated
gesetzt. So werden flüssigere Übergänge zwischen Textanimationen ermöglicht. Verwenden Sie Modifier.graphicsLayer{ }
, um den Text zu übersetzen, zu drehen oder zu 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
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
Mit AnimatedContent
kannst du zwischen verschiedenen Composeables animieren. Wenn du nur einen Standard-Überblendungseffekt zwischen Composeables haben möchtest, verwende 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 verschiedene Arten von Ein- und Ausblendungsübergängen angezeigt werden. Weitere Informationen finden Sie in der Dokumentation zu AnimatedContent
oder in diesem Blogpost zu
AnimatedContent
.
Animationen beim Wechseln zwischen verschiedenen Zielen
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
Verwenden Sie rememberInfiniteTransition
mit einem infiniteRepeatable
animationSpec
, um die Animation fortlaufend zu wiederholen. Ändern Sie RepeatModes
, um anzugeben, wie vor- und zurückgegangen werden 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 ein Composeable in die Komposition eintritt. Los gehts
eine Animation beim Start einer zusammensetzbaren Funktion.
Statusänderung. Animatable
mit der Methode animateTo
verwenden, um die Animation beim Starten zu starten:
val alphaAnimation = remember { Animatable(0f) } LaunchedEffect(Unit) { alphaAnimation.animateTo(1f) } Box( modifier = Modifier.graphicsLayer { alpha = alphaAnimation.value } )
Sequenzielle Animationen erstellen
Verwenden Sie die Animatable
-Coroutinen-APIs, um sequenzielle oder parallele Animationen auszuführen. Wenn Sie animateTo
nacheinander auf Animatable
anwenden, wartet jede Animation, bis die vorherigen Animationen abgeschlossen sind, bevor sie fortfährt.
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)) }
Parallele Animationen erstellen
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 verwenden, um viele verschiedene Unterkunftsanimationen gleichzeitig zu steuern. 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.
Berücksichtigen Sie die verschiedenen Phasen des Komponierens: Komposition, Layout und Zeichnen. Wenn sich durch Ihre Animation die Layoutphase ändert, müssen alle betroffenen Composables neu layoutet und neu gezeichnet werden. Wenn die Animation in der Zeichenphase erfolgt, ist sie standardmäßig leistungsfähiger als wenn Sie die Animation in der Layoutphase ausführen würden, da insgesamt weniger Arbeit anfällt.
Damit Ihre App während der Animation so wenig wie möglich belastet wird, wählen Sie nach Möglichkeit die Lambda-Version eines Modifier
aus. 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 physikbasierte Animationen wirken natürlicher. Sie können auch unterbrochen werden, da sie die aktuelle Geschwindigkeit des Objekts anstelle einer festen Zeit berücksichtigen.
Wenn Sie die Standardeinstellung überschreiben möchten, können Sie mit allen oben genannten Animation APIs einen animationSpec
festlegen, um die Ausführung einer Animation anzupassen. So können Sie beispielsweise festlegen, dass sie über einen bestimmten Zeitraum ausgeführt werden soll oder dass sie federleichter sein soll.
Im Folgenden finden Sie eine Zusammenfassung der verschiedenen animationSpec
-Optionen:
spring
: Physikbasierte Animationen, die Standardeinstellung für alle Animationen. Sie können die Steifigkeit oder das Dämpfungsverhältnis ändern, um ein anderes Erscheinungsbild der Animation zu erzielen.tween
(kurz für zwischen): Animationsdauer nach Dauer, animiert mit der FunktionEasing
zwischen zwei Werten.keyframes
: Spezifikation zum Angeben von Werten an bestimmten Schlüsselpunkten in einer Animation.repeatable
: Dauerbasierte Spezifikation, die eine bestimmte Anzahl von Malen ausgeführt wird, die durchRepeatMode
angegeben wird.infiniteRepeatable
: Dauerbasierte Spezifikation, die unbegrenzt läuft.snap
: Andockt sofort und ohne Animation an den Endwert.
Weitere Informationen zu animationSpecs finden Sie in der vollständigen Dokumentation.
Weitere Informationen
Weitere Beispiele für lustige Animationen in „Schreiben“ finden Sie hier:
- 5 schnelle Animationen in Compose
- Jellyfish in „Compose“ bewegen
AnimatedContent
in der Zeichenansicht anpassen- Einführung in die Übergänge in Compose