Funkcja tworzenia wiadomości ma wiele wbudowanych mechanizmów animacji i może być przytłaczająca. musisz wybrać. Poniżej znajdziesz listę typowych zastosowań animacji. Dla: bardziej szczegółowe informacje na temat pełnego zestawu różnych dostępnych opcji interfejsu API. przeczytaj pełną dokumentację tworzenia animacji.
Animowanie wspólnych właściwości komponentów
Compose zapewnia wygodne interfejsy API, które pozwalają rozwiązać wiele typowych problemów w przypadku animacji. W tej sekcji pokazujemy, jak animować typowe właściwości elementu kompozycyjnego.
animacja pojawiania się i znikania,
Użyj AnimatedVisibility
, aby ukryć lub wyświetlić funkcję kompozycyjną. Dzieci w AnimatedVisibility
mogą używać Modifier.animateEnterExit()
do własnych przejść wjazdowych lub wyjazdowych.
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 // ... }
Parametry wejścia i wyjścia parametru AnimatedVisibility
umożliwiają skonfigurowanie
funkcja kompozycyjna zachowuje się, gdy pojawia się i znika. Przeczytaj w całości
dokumentacji.
Inną opcją animowania widoczności funkcji kompozycyjnej jest
alfa na przestrzeni czasu za pomocą 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) ) { }
Zmiana wartości alfa wiąże się jednak z tym, że kompozybilny element pozostanie w kompozycji i nadal będzie zajmować wyznaczoną mu przestrzeń. Może to spowodować, że czytniki ekranu i inne mechanizmy ułatwień dostępu nadal będą traktować element jako element na ekranie. Z drugiej strony AnimatedVisibility
w końcu usuwa
elementu z kompozycji.
Animowanie koloru tła
val animatedColor by animateColorAsState( if (animateBackgroundColor) colorGreen else colorBlue, label = "color" ) Column( modifier = Modifier.drawBehind { drawRect(animatedColor) } ) { // your composable here }
Ta opcja jest bardziej wydajna niż Modifier.background()
.
Dla jednego ustawienia kolorów dozwolone jest użycie koloru Modifier.background()
, ale gdy
animowanie koloru w czasie, może spowodować większą liczbę zmian kompozycji niż
niezbędną.
Informacje o animowaniu koloru tła w nieskończoności znajdziesz w sekcji powtarzanie animacji.
Animuj rozmiar elementu kompozycyjnego
Funkcja tworzenia umożliwia animowanie rozmiaru elementów kompozycyjnych na kilka różnych sposobów. Używaj
animateContentSize()
– animacje między zmianami rozmiaru kompozycyjnego.
Jeśli na przykład masz pole zawierające tekst, które można rozwinąć od 1 do
Możesz użyć wielu linii Modifier.animateContentSize()
, aby zwiększyć płynność
przejście:
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 } ) { }
Możesz też użyć atrybutu AnimatedContent
z SizeTransform
, aby opisać
jak powinny
wprowadzać się zmiany rozmiaru.
Animuj położenie funkcji kompozycyjnej
Aby animować położenie funkcji kompozycyjnej, użyj operatora Modifier.offset{ }
w połączeniu z
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 } )
Aby elementy kompozycyjne nie były rysowane nad ani pod innymi
elementów kompozycyjnych podczas animowania pozycji lub rozmiaru, użyj funkcji Modifier.layout{ }
. Ten modyfikator rozszerza zmiany rozmiaru i położenia na element nadrzędny, który wpływa na inne elementy podrzędne.
Na przykład jeśli przenosisz element Box
w elemencie Column
i innych elementach podrzędnych
które musisz przesunąć, gdy przesuwa się Box
, uwzględnij informacje o przesunięciu
Modifier.layout{ }
w następujący sposób:
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) ) }
Animowanie wypełniania kompozytu
Aby animować dopełnienie funkcji kompozycyjnej, użyj właściwości animateDpAsState
w połączeniu z
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 } )
Animuj wysokość elementu kompozycyjnego
Aby animować wysokość elementu kompozycyjnego, użyj funkcji animateDpAsState
w połączeniu z
Modifier.graphicsLayer{ }
W przypadku jednorazowych zmian wysokości użyj opcji Modifier.shadow()
. Jeśli animujesz cień, za pomocą funkcji
Modyfikator Modifier.graphicsLayer{ }
jest skuteczniejszą opcją.
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) ) { }
Możesz też użyć funkcji kompozycyjnej Card
i ustawić właściwość wysokości nad poziomem morza na
różne wartości dla każdego stanu.
Animowanie skali, przesunięcia lub obrotu tekstu
Podczas animowania skali, przesunięcia lub obrotu tekstu ustaw textMotion
od TextStyle
do TextMotion.Animated
. Dzięki temu przejścia między animacjami tekstu będą płynniejsze. Użyj Modifier.graphicsLayer{ }
, aby obrócić lub zmienić rozmiar tekstu albo go przetłumaczyć.
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) ) }
Kolor tekstu w animacji
Aby animować kolor tekstu, użyj funkcji lambda color
w komponencie kompozycyjnym 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 }, // ... )
Przełączanie się między różnymi typami treści
Użyj AnimatedContent
, aby przełączać się między różnymi elementami kompozycyjnymi, jeśli:
aby standardowe rozjaśnianie elementów kompozycyjnych, użyj 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
można dostosować, tak aby wyświetlać wiele różnych rodzajów wiadomości
przejściach typu wyjściowego. Więcej informacji znajdziesz w dokumentacji dotyczącej AnimatedContent
lub w tym poście na blogu na temat AnimatedContent
.
animacje podczas nawigacji do różnych miejsc docelowych.
Aby animować przejścia między składanymi, gdy używasz artefaktu navigation-compose, określ enterTransition
i exitTransition
w składanym. Możesz też ustawić animację domyślną
używany w przypadku wszystkich miejsc docelowych na najwyższym poziomie (NavHost
):
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( // ... ) } }
Istnieje wiele rodzajów przejść, które można stosować do treści wchodzących i wychodzących. Więcej informacji znajdziesz w dokumentacji.
Powtarzanie animacji
Aby animacja była powtarzana w nieskończoność, użyj rememberInfiniteTransition
z infiniteRepeatable
animationSpec
. Zmień RepeatModes
na
i określić, jak ma się to odbywać.
Użyj finiteRepeatable
, aby powtórzyć określoną liczbę razy.
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 }
Rozpoczęcie animacji podczas uruchamiania komponentu
LaunchedEffect
jest wykonywane, gdy element kompozycyjny wchodzi do kompozycji. Zaczyna się
możesz utworzyć animację przy uruchomieniu funkcji kompozycyjnej,
zmiany stanu. Użycie Animatable
z metodą animateTo
do uruchamiania
animacja przy uruchomieniu:
val alphaAnimation = remember { Animatable(0f) } LaunchedEffect(Unit) { alphaAnimation.animateTo(1f) } Box( modifier = Modifier.graphicsLayer { alpha = alphaAnimation.value } )
Tworzenie animacji sekwencyjnych
Używaj wewnętrznych interfejsów API Animatable
do wykonywania sekwencyjnych lub równoczesnych
ani animacji. Wywołuję animateTo
(Animatable
) jeden po drugim
Kolejne animacje będą czekać na zakończenie poprzednich animacji .
Dzieje się tak, ponieważ jest to funkcja zawieszenia.
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { alphaAnimation.animateTo(1f) yAnimation.animateTo(100f) yAnimation.animateTo(500f, animationSpec = tween(100)) }
Tworzenie animacji równoczesnych
użyj wewnętrznych interfejsów API (Animatable#animateTo()
lub animate
);
interfejs API Transition
do tworzenia równoczesnych animacji. Jeśli w kontekście coroutine używasz wielu funkcji launch, animacje są uruchamiane jednocześnie:
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { launch { alphaAnimation.animateTo(1f) } launch { yAnimation.animateTo(100f) } }
Możesz użyć interfejsu API updateTransition
, aby za pomocą tego samego stanu sterować jednocześnie wieloma animacjami w różnych usługach. Animowany przykład poniżej
2 właściwości kontrolowane przez zmianę stanu: rect
i 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 } }
Optymalizacja wydajności animacji
Animacje w edytorze mogą powodować problemy z wydajnością. Wynika to z natury animacji: szybkie przesuwanie lub zmienianie pikseli na ekranie. klatka po klatce, aby stworzyć iluzję ruchu.
Zastanów się nad różnymi fazami tworzenia kompozycji: kompozycji, układu i rysowania. Jeśli animacja zmienia fazę układu, wymaga ponownego rozmieszczenia i narysowania wszystkich dotkniętych kompozytowych komponentów. Jeśli animacja występuje w fazie rysowania, domyślnie będzie działać wydajniej niż w fazie układu, ponieważ będzie miała mniej pracy do wykonania.
Aby zapewnić, że podczas animacji aplikacja będzie wykonywać jak najmniej działań, w miarę możliwości wybieraj wersję lambda funkcji Modifier
. Spowoduje to pominięcie ponownego tworzenia kompozycji i wykonanie animacji poza fazą tworzenia kompozycji. W przeciwnym razie użyj parametru Modifier.graphicsLayer{ }
, ponieważ ten modyfikator zawsze działa w fazie rysowania. Więcej informacji na ten temat znajdziesz w sekcji o odwracaniu odczytów w artykule
zapoznaj się z dokumentacją wyników.
Zmienianie czasu animacji
Domyślnie kompozytor używa animacji elastycznej w przypadku większości animacji. Sprężyny lub animacje oparte na fizyce wydają się bardziej naturalne. Mogą być też przerywane, ponieważ uwzględniają bieżącą prędkość obiektu zamiast stałego czasu.
Jeśli chcesz zastąpić ustawienia domyślne, użyj wszystkich interfejsów API animacji pokazanych powyżej
możesz ustawić animationSpec
, aby dostosować sposób działania animacji,
czy wolisz, aby wykonywały się przez określony czas, czy były bardziej dynamiczne.
Oto podsumowanie różnych opcji animationSpec
:
spring
: animacja oparta na fizyce, domyślna dla wszystkich animacji. Ty można zmienić sztywność lub współczynnik tłumienia, aby uzyskać inną animację wygląd i styl.tween
(skrót od Between): animacja zależna od czasu trwania, animacja między 2 wartościami za pomocą funkcjiEasing
.keyframes
: specyfikacja określająca wartości w określonych kluczowych punktach animacji.repeatable
: specyfikacja oparta na czasie, która jest odtwarzana określoną liczbę razy (określoną przezRepeatMode
).infiniteRepeatable
: specyfikacja oparta na czasie, która działa bez końca.snap
: wartość końcowa jest ustawiana natychmiast, bez animacji.
Więcej informacji na temat animationSpecs znajdziesz w pełnej dokumentacji.
Dodatkowe materiały
Więcej przykładów zabawnych animacji w Compose:
- 5 szybkich animacji w sekcji Nowy post
- Poruszanie się wśród meduzy
- Dostosowywanie elementu
AnimatedContent
w funkcji Compose - Wygładzanie funkcji wygładzania w narzędziu Compose