Compose כולל רכיבי Composable ומשנים מובנים לטיפול בתרחישי שימוש נפוצים באנימציה.
פונקציות קומפוזיציה מובנות עם אנימציה
יצירת אנימציה של הופעה והיעלמות באמצעות AnimatedVisibility

רכיב ה-Composable
AnimatedVisibility
מנפיש את ההופעה וההיעלמות של התוכן שלו.
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 // ... }
כברירת מחדל, התוכן מופיע בהדרגה ומתרחב, ונעלם בהדרגה ומתכווץ. אפשר להתאים אישית את המעבר על ידי ציון הערכים
EnterTransition
ו-
ExitTransition
.
var visible by remember { mutableStateOf(true) } val density = LocalDensity.current AnimatedVisibility( visible = visible, enter = slideInVertically { // Slide in from 40 dp from the top. with(density) { -40.dp.roundToPx() } } + expandVertically( // Expand from the top. expandFrom = Alignment.Top ) + fadeIn( // Fade in with the initial alpha of 0.3f. initialAlpha = 0.3f ), exit = slideOutVertically() + shrinkVertically() + fadeOut() ) { Text( "Hello", Modifier .fillMaxWidth() .height(200.dp) ) }
כפי שאפשר לראות בדוגמה שלמעלה, אפשר לשלב כמה אובייקטים מסוג EnterTransition
או ExitTransition
עם אופרטור +
, וכל אחד מהם מקבל פרמטרים אופציונליים להתאמה אישית של ההתנהגות שלו. מידע נוסף מופיע במאמרי העזרה.
EnterTransition
וExitTransition
דוגמאות
בנוסף, AnimatedVisibility
מציע וריאציה שלוקחת MutableTransitionState
. כך אפשר להפעיל אנימציה ברגע שהתג AnimatedVisibility
נוסף לעץ הקומפוזיציה. הוא שימושי גם כדי לראות את מצב האנימציה.
// Create a MutableTransitionState<Boolean> for the AnimatedVisibility. val state = remember { MutableTransitionState(false).apply { // Start the animation immediately. targetState = true } } Column { AnimatedVisibility(visibleState = state) { Text(text = "Hello, world!") } // Use the MutableTransitionState to know the current animation state // of the AnimatedVisibility. Text( text = when { state.isIdle && state.currentState -> "Visible" !state.isIdle && state.currentState -> "Disappearing" state.isIdle && !state.currentState -> "Invisible" else -> "Appearing" } ) }
הוספת אנימציה לכניסה וליציאה לילדים
תוכן בתוך AnimatedVisibility
(צאצאים ישירים או עקיפים) יכול להשתמש במאפיין
animateEnterExit
כדי לציין התנהגות שונה של אנימציה לכל אחד מהם. האפקט הוויזואלי של כל אחד מהצאצאים האלה הוא שילוב של האנימציות שצוינו ברכיב AnimatedVisibility
composable ושל אנימציות הכניסה והיציאה של הצאצא עצמו.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // Fade in/out the background and the foreground. Box( Modifier .fillMaxSize() .background(Color.DarkGray) ) { Box( Modifier .align(Alignment.Center) .animateEnterExit( // Slide in/out the inner box. enter = slideInVertically(), exit = slideOutVertically() ) .sizeIn(minWidth = 256.dp, minHeight = 64.dp) .background(Color.Red) ) { // Content of the notification… } } }
במקרים מסוימים, יכול להיות שתרצו להגדיר את AnimatedVisibility
כך שלא יחולו אנימציות בכלל, כדי שכל ילד יוכל להגדיר אנימציות ייחודיות משלו באמצעות animateEnterExit
. כדי לעשות את זה, מציינים את EnterTransition.None
ואת ExitTransition.None
ב-composable AnimatedVisibility
.
הוספת הנפשה בהתאמה אישית
אם רוצים להוסיף אפקטים מותאמים אישית של אנימציה מעבר לאנימציות המובנות של כניסה ויציאה, אפשר לגשת למופע הבסיסי של Transition
דרך המאפיין transition
בתוך lambda התוכן של AnimatedVisibility
. כל מצבי האנימציה שנוספו למופע Transition יפעלו בו-זמנית עם אנימציות הכניסה והיציאה של AnimatedVisibility
. AnimatedVisibility
ממתין עד שכל האנימציות ב-Transition
מסתיימות לפני שהוא מסיר את התוכן שלו.
באנימציות יציאה שנוצרו בנפרד מ-Transition
(למשל באמצעות animate*AsState
), AnimatedVisibility
לא יוכל להביא אותן בחשבון, ולכן יכול להיות שהוא יסיר את התוכן שניתן להרכבה לפני שהן יסתיימו.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // this: AnimatedVisibilityScope // Use AnimatedVisibilityScope#transition to add a custom animation // to the AnimatedVisibility. val background by transition.animateColor(label = "color") { state -> if (state == EnterExitState.Visible) Color.Blue else Color.Gray } Box( modifier = Modifier .size(128.dp) .background(background) ) }
פרטים על Transition
זמינים במאמר בנושא updateTransition.
יצירת אנימציה על סמך מצב היעד באמצעות AnimatedContent
הקומפוזיציה AnimatedContent
מנפישה את התוכן שלה כשהוא משתנה על סמך מצב היעד.
Row { var count by remember { mutableIntStateOf(0) } Button(onClick = { count++ }) { Text("Add") } AnimatedContent( targetState = count, label = "animated content" ) { targetCount -> // Make sure to use `targetCount`, not `count`. Text(text = "Count: $targetCount") } }
חשוב לזכור שתמיד צריך להשתמש בפרמטר lambda ולשקף אותו לתוכן. ה-API משתמש בערך הזה כמפתח לזיהוי התוכן שמוצג כרגע.
כברירת מחדל, התוכן הראשוני נחלש בהדרגה ואז התוכן של היעד מתחזק בהדרגה (ההתנהגות הזו נקראת החלשה הדרגתית). כדי לשנות את אופן הפעולה של האנימציה, מציינים אובייקט ContentTransform
בפרמטר transitionSpec
. אפשר ליצור ContentTransform
על ידי שילוב של EnterTransition
עם ExitTransition
באמצעות פונקציית ה-infix with
. אפשר להחיל את SizeTransform
על ContentTransform
על ידי צירוף שלו באמצעות פונקציית ה-infix using
.
AnimatedContent( targetState = count, transitionSpec = { // Compare the incoming number with the previous number. if (targetState > initialState) { // If the target number is larger, it slides up and fades in // while the initial (smaller) number slides up and fades out. slideInVertically { height -> height } + fadeIn() togetherWith slideOutVertically { height -> -height } + fadeOut() } else { // If the target number is smaller, it slides down and fades in // while the initial number slides down and fades out. slideInVertically { height -> -height } + fadeIn() togetherWith slideOutVertically { height -> height } + fadeOut() }.using( // Disable clipping since the faded slide-in/out should // be displayed out of bounds. SizeTransform(clip = false) ) }, label = "animated content" ) { targetCount -> Text(text = "$targetCount") }
EnterTransition
מגדיר איך תוכן היעד צריך להופיע, ו-ExitTransition
מגדיר איך התוכן הראשוני צריך להיעלם. בנוסף לכל הפונקציות של EnterTransition
ו-ExitTransition
שזמינות ב-AnimatedVisibility
, ב-AnimatedContent
יש גם את slideIntoContainer
ואת slideOutOfContainer
.
אלה חלופות נוחות לפונקציות slideInHorizontally/Vertically
ו-slideOutHorizontally/Vertically
, שמחשבות את מרחק ההזזה על סמך הגדלים של התוכן הראשוני והתוכן של היעד של התוכן AnimatedContent
.
SizeTransform
מגדיר את האופן שבו הגודל צריך להיות מונפש בין התוכן הראשוני לבין תוכן היעד. כשיוצרים את האנימציה, יש גישה גם לגודל ההתחלתי וגם לגודל היעד. המאפיין SizeTransform
קובע גם אם התוכן ייחתך לגודל הרכיב במהלך האנימציות.
var expanded by remember { mutableStateOf(false) } Surface( color = MaterialTheme.colorScheme.primary, onClick = { expanded = !expanded } ) { AnimatedContent( targetState = expanded, transitionSpec = { fadeIn(animationSpec = tween(150, 150)) togetherWith fadeOut(animationSpec = tween(150)) using SizeTransform { initialSize, targetSize -> if (targetState) { keyframes { // Expand horizontally first. IntSize(targetSize.width, initialSize.height) at 150 durationMillis = 300 } } else { keyframes { // Shrink vertically first. IntSize(initialSize.width, targetSize.height) at 150 durationMillis = 300 } } } }, label = "size transform" ) { targetExpanded -> if (targetExpanded) { Expanded() } else { ContentIcon() } } }
הוספת אנימציה למעברים של רכיבי צאצא בכניסה וביציאה
בדומה ל-AnimatedVisibility
, משנה המאפיין animateEnterExit
זמין בתוך פונקציית ה-lambda של התוכן ב-AnimatedContent
. אפשר להשתמש באפשרות הזו כדי להחיל את EnterAnimation
וExitAnimation
על כל אחד מהצאצאים הישירים או העקיפים בנפרד.
הוספת הנפשה בהתאמה אישית
בדומה ל-AnimatedVisibility
, השדה transition
זמין בתוך פונקציית ה-lambda של התוכן AnimatedContent
. אפשר להשתמש באפשרות הזו כדי ליצור אפקט אנימציה מותאם אישית שפועל בו-זמנית עם המעבר AnimatedContent
. פרטים נוספים זמינים במאמר בנושא updateTransition.
יצירת אנימציה בין שני פריסות באמצעות Crossfade
Crossfade
אנימציה של מעבר בין שני פריסות עם אנימציית הדהייה. החלפת התוכן מתבצעת באמצעות אנימציית מעבר הדרגתי, על ידי שינוי הערך שמועבר לפרמטר current
.
var currentPage by remember { mutableStateOf("A") } Crossfade(targetState = currentPage, label = "cross fade") { screen -> when (screen) { "A" -> Text("Page A") "B" -> Text("Page B") } }
אמצעים מובנים לשינוי אנימציות
הנפשה של שינויים בגודל של רכיבים שאפשר להרכיב עם animateContentSize

המשנה animateContentSize
יוצר אנימציה של שינוי גודל.
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 } ) { }
הנפשות של פריטים ברשימה
אם אתם רוצים להנפיש את הסידור מחדש של פריטים בתוך רשימה או רשת עצלה, כדאי לעיין במסמכי התיעוד בנושא הנפשה של פריטים בפריסה עצלה.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- אנימציות מבוססות-ערך
- אנימציות בכתיבה
- תמיכה בכלי אנימציה {:#tooling}