Compose verfügt über viele integrierte Animationsmechanismen und es kann schwierig sein, zu wissen, welchen man auswählen soll. Nachfolgend finden Sie eine Liste häufiger Anwendungsfälle für Animationen. Ausführlichere Informationen zu den verschiedenen verfügbaren API-Optionen finden Sie in der vollständigen Dokumentation zum Erstellen einer Animation.
Häufige zusammensetzbare Eigenschaften animieren
Compose bietet praktische APIs, mit denen Sie viele gängige Animationsanwendungsfälle lösen können. In diesem Abschnitt wird gezeigt, wie Sie allgemeine Eigenschaften einer zusammensetzbaren Funktion animieren.
Animation zum Ein-/Verschwinden
Mit AnimatedVisibility
können Sie eine zusammensetzbare Funktion ein- oder ausblenden. Untergeordnete Elemente innerhalb von AnimatedVisibility
können Modifier.animateEnterExit()
für ihren eigenen Eingang oder Ausgang 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 sich eine zusammensetzbare Funktion verhält, wenn sie ein- und ausgeblendet wird. Weitere Informationen finden Sie in der vollständigen Dokumentation.
Eine weitere Option zum Animieren der Sichtbarkeit einer zusammensetzbaren Funktion besteht darin, die Alphaversion im Zeitverlauf mit animateFloatAsState
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) ) { }
Beim Ändern der Alpha-Phase bleibt die zusammensetzbare Funktion jedoch in der Komposition bestehen und belegt weiterhin den Raum, in dem sie angelegt ist. Dies kann dazu führen, dass Screenreader und andere Bedienungshilfen das Element auf dem Bildschirm weiterhin berücksichtigen. Andererseits entfernt AnimatedVisibility
das Element schließlich aus der Komposition.
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 einzelne Farbeinstellung akzeptabel. Wenn Sie jedoch eine Farbe im Zeitverlauf animieren, kann dies zu mehr Neuzusammensetzungen als nötig führen.
Wie Sie die Hintergrundfarbe unbegrenzt animieren, erfahren Sie unter Animationsabschnitt wiederholen.
Größe einer zusammensetzbaren Funktion animieren
Mit der Funktion „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.
Bei einem Feld mit Text, der sich beispielsweise von einer Zeile auf mehrere Zeilen erweitern lässt, können Sie mit Modifier.animateContentSize()
einen weicheren Übergang erzielen:
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 stattfinden sollen.
Position der zusammensetzbaren Funktion animieren
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 möchten, dass zusammensetzbare Funktionen bei der Animation von Position oder Größe nicht über oder unter anderen zusammensetzbaren Funktionen eingeblendet werden, verwenden Sie Modifier.layout{ }
. Dadurch werden Änderungen an Größe und Position an das übergeordnete Element weitergegeben, was sich dann auf andere untergeordnete Elemente auswirkt.
Wenn Sie beispielsweise ein Box
innerhalb einer Column
verschieben und die anderen untergeordneten Elemente verschoben werden müssen, wenn das Box
verschoben wird, fügen Sie die Versatzinformationen mit Modifier.layout{ }
so hinzu:
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) ) }
Abstand in 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{ }
. Für einmalige Höhenänderungen verwenden Sie Modifier.shadow()
. Wenn Sie den Schatten animieren, ist der Modifier.graphicsLayer{ }
-Modifikator 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 das Höhenattribut auf verschiedene Werte pro Status festlegen.
Textskalierung, Verschiebung oder Drehung animieren
Wenn Sie den Maßstab, die Übersetzung oder die Drehung von Text animieren möchten, setzen Sie den textMotion
-Parameter für TextStyle
auf TextMotion.Animated
. So sind flüssigere Übergänge zwischen Textanimationen Mit Modifier.graphicsLayer{ }
können Sie den Text ü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
Verwende zum Animieren der Textfarbe das Lambda color
für die zusammensetzbare 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
Verwenden Sie AnimatedContent
, um zwischen verschiedenen zusammensetzbaren Funktionen zu animieren. Wenn Sie nur eine Standardüberblendung zwischen zusammensetzbaren Funktionen vornehmen 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 verschiedene Arten von Ein- und Ausgangsübergängen angezeigt werden. Weitere Informationen finden Sie in der Dokumentation zu AnimatedContent
oder in diesem Blogpost zu
AnimatedContent
.
Während der Navigation zu verschiedenen Zielen Animationen erstellen
Wenn Sie bei Verwendung des Artefakts navigation-compose Übergänge zwischen zusammensetzbaren Funktionen animieren möchten, geben Sie für eine zusammensetzbare Funktion enterTransition
und exitTransition
an. Sie können auch die Standardanimation festlegen, die für alle Ziele auf der obersten Ebene NavHost
verwendet wird:
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 Eingabe- und Exit-Übergängen, die unterschiedliche Auswirkungen auf die eingehenden und ausgehenden Inhalte haben. Weitere Informationen finden Sie in der Dokumentation.
Animation wiederholen
Wenn du die Animation kontinuierlich wiederholen möchtest, verwende rememberInfiniteTransition
mit einem infiniteRepeatable
-animationSpec
. Ändern Sie RepeatModes
, um festzulegen, wie vor- und zurückgegangen werden soll.
Mit finiteRepeatable
wiederholen Sie den Vorgang eine bestimmte Anzahl von Malen.
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. Beim Start einer zusammensetzbaren Funktion wird eine Animation gestartet. Sie können damit die Änderung des Animationsstatus steuern. Verwenden Sie Animatable
mit der Methode animateTo
, um die Animation beim Start 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
-Coroutine-APIs, um sequenzielle oder gleichzeitige Animationen auszuführen. Wenn animateTo
im Animatable
nacheinander aufgerufen wird, wartet jede Animation, bis die vorherigen Animationen beendet sind, bevor sie fortgesetzt wird .
Das liegt daran, dass es sich um eine Anhalten-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)) }
Animationen gleichzeitig erstellen
Verwenden Sie die Coroutine-APIs (Animatable#animateTo()
oder animate
) oder die Transition
API, um gleichzeitige Animationen zu erreichen. Wenn Sie mehrere Startfunktionen in einem Koroutinenkontext verwenden, werden die Animationen gleichzeitig gestartet:
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { launch { alphaAnimation.animateTo(1f) } launch { yAnimation.animateTo(100f) } }
Sie können die updateTransition
API verwenden, um denselben Status zu verwenden und viele verschiedene Attributanimationen gleichzeitig auszuführen. Im folgenden Beispiel werden zwei Eigenschaften animiert, 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 der Funktion „Compose“ können zu Leistungsproblemen führen. Dies liegt an der Art einer Animation: schnelles Bewegen oder Ändern von Pixeln auf dem Bildschirm und Frame für Frame, um den Eindruck einer Bewegung zu erzeugen.
Sehen Sie sich die verschiedenen Phasen des Verfassens an: Komposition, Layout und Zeichnen. Wenn sich die Layoutphase durch die Animation ändert, müssen alle betroffenen zusammensetzbaren Funktionen neu gestaltet und gezeichnet werden. Wenn die Animation in der Zeichenphase stattfindet, ist sie standardmäßig leistungsfähiger als die Animation in der Layoutphase, da insgesamt weniger Arbeit erforderlich wäre.
Damit deine App bei der Animation so wenig wie möglich ausführt, wähle nach Möglichkeit die Lambda-Version einer Modifier
aus. Dadurch wird die Neuzusammensetzung übersprungen und die Animation wird außerhalb der Zusammensetzungsphase ausgeführt. Verwenden Sie andernfalls Modifier.graphicsLayer{ }
, da dieser Modifikator immer in der Zeichenphase ausgeführt wird. Weitere Informationen dazu finden Sie in der Leistungsdokumentation im Abschnitt Aussetzen von Lesevorgängen.
Timing der Animation ändern
Standardmäßig werden für die meisten Animationen Frühlingsanimationen verwendet. Federn, also physikbasierte
Animationen, wirken natürlicher. Sie sind auch unterbrechbar, da sie die aktuelle Geschwindigkeit des Objekts anstelle einer festen Zeit berücksichtigen.
Wenn Sie die Standardeinstellung überschreiben möchten, können Sie bei allen oben gezeigten Animations-APIs ein animationSpec
festlegen, um die Ausführung einer Animation anzupassen. Dabei spielt es keine Rolle, ob die Animation über eine bestimmte Dauer oder mit mehr Schwingungen ausgeführt werden soll.
Im Folgenden finden Sie eine Zusammenfassung der verschiedenen animationSpec
-Optionen:
spring
: Physikbasierte Animationen, Standard für alle Animationen Sie können die Steifheit oder das dampingRatio ändern, um ein anderes Erscheinungsbild der Animation zu erreichen.tween
(kurz für between): Dauerbasierte Animation, wird zwischen zwei Werten mit einerEasing
-Funktion animiert.keyframes
: Spezifikation zur Angabe von Werten an bestimmten wichtigen Punkten in einer Animation.repeatable
: Dauerbasierte Spezifikation, die eine bestimmte Anzahl von Ausführungen ausführt, angegeben durchRepeatMode
.infiniteRepeatable
: Dauerbasierte Spezifikation, die unbegrenzt ausgeführt wird.snap
: wird direkt und ohne Animation an den Endwert angedockt.
Weitere Informationen zu animationSpecs finden Sie in der vollständigen Dokumentation.
Weitere Informationen
Weitere Beispiele für lustige Animationen in der Funktion „Compose“ finden Sie hier:
- 5 schnelle Animationen in der Funktion „Compose“
- Jellyfish in Compose verschieben
AnimatedContent
in Compose anpassen- Easing-Funktionen in Compose