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