Compose כולל רכיבים מורכבים ומשתני מודיפיקטור מובנים לטיפול בתרחישי שימוש נפוצים של אנימציה.
תכנים קומפוזביליים מובנים באנימציה
אנימציה של הופעה והיעלמות באמצעות AnimatedVisibility
הרכיב המודד 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
עם האנימציות של הילד או הילדה לכניסה וליציאה.
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
. מצבי האנימציה שנוספו למכונה של ה-מעבר יפעלו בו-זמנית עם אנימציות הכניסה והיציאה של 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
באמצעות פונקציית הביניים with
. אפשר להחיל את SizeTransform
על ContentTransform
באמצעות הצמדה שלה באמצעות פונקציית הביניים 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
זמין בתוך פונקציית הלמהדה של התוכן של 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 מושבת
- אנימציות מבוססות-ערך
- אנימציות ב-Compose
- תמיכה בכלים ליצירת אנימציות {:#tooling}