כדי להתאים אישית את האופן שבו האנימציה של המעבר בין הרכיבים המשותפים פועלת, יש כמה פרמטרים שאפשר להשתמש בהם כדי לשנות את המעבר בין הרכיבים המשותפים.
מפרט האנימציה
כדי לשנות את מפרט האנימציה שמשמש לתנועה של הגודל והמיקום, אתם יכולים לציין פרמטר boundsTransform אחר ב-Modifier.sharedElement().
כך מקבלים את המיקום הראשוני של Rect ואת מיקום היעד של Rect.
לדוגמה, כדי שהטקסט בדוגמה הקודמת יזוז בתנועה קשתית, מציינים את הפרמטר boundsTransform לשימוש במפרט keyframes:
val textBoundsTransform = BoundsTransform { initialBounds, targetBounds -> keyframes { durationMillis = boundsAnimationDurationMillis initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing targetBounds at boundsAnimationDurationMillis } } Text( "Cupcake", fontSize = 28.sp, modifier = Modifier.sharedBounds( rememberSharedContentState(key = "title"), animatedVisibilityScope = animatedVisibilityScope, boundsTransform = textBoundsTransform ) )
אפשר להשתמש בכל AnimationSpec. בדוגמה הזו נעשה שימוש במפרט של keyframes.
boundsTransformמצב שינוי גודל
כשמפעילים אנימציה בין שני גבולות משותפים, אפשר להגדיר את הפרמטר resizeMode לערך RemeasureToBounds או ScaleToBounds. הפרמטר הזה קובע איך הרכיב המשותף עובר בין שני המצבים. ScaleToBounds קודם מודד את פריסת הצאצא עם אילוצי ה-lookahead (או היעד). לאחר מכן, הפריסה היציבה של הצאצא משתנה בהתאם לגבולות המשותפים.
אפשר לחשוב על ScaleToBounds כ "סולם גרפי" בין המצבים.
לעומת זאת, RemeasureToBounds מודד מחדש ומסדר מחדש את פריסת הצאצא של sharedBounds עם אילוצים קבועים מונפשים על סמך גודל היעד. המדידה מחדש מופעלת בעקבות שינוי בגודל הגבולות, שיכול להתרחש בכל פריים.
לרכיבי Text מומלץ להשתמש ב-ScaleToBounds, כי הוא מונע פריסה מחדש וזרימה מחדש של הטקסט לשורות שונות. מומלץ להשתמש ב-RemeasureToBounds לגבולות עם יחסי גובה-רוחב שונים, ואם רוצים המשכיות חלקה בין שני הרכיבים המשותפים.
ההבדל בין שני מצבי שינוי הגודל מוצג בדוגמאות הבאות:
|
|
|---|---|
הפעלה והשבתה של רכיבים משותפים באופן דינמי
כברירת מחדל, sharedElement() ו-sharedBounds() מוגדרים להנפיש את השינויים בפריסה בכל פעם שנמצא מפתח תואם במצב היעד. עם זאת, יכול להיות שתרצו להשבית את האנימציה הזו באופן דינמי על סמך תנאים ספציפיים, כמו כיוון הניווט או המצב הנוכחי של ממשק המשתמש.
כדי לקבוע אם המעבר של הרכיב המשותף יתרחש, אתם יכולים להתאים אישית את ה-SharedContentConfig שמועבר אל rememberSharedContentState(). המאפיין isEnabled קובע אם הרכיב המשותף פעיל.
בדוגמה הבאה מוסבר איך להגדיר מעבר משותף שמופעל רק כשעוברים בין מסכים ספציפיים (למשל, רק מ-A ל-B), ומושבת במסכים אחרים.
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
כברירת מחדל, אם רכיב משותף מושבת במהלך אנימציה, הוא עדיין משלים את האנימציה הנוכחית כדי למנוע הסרה בטעות של אנימציות פעילות. אם אתם צריכים להסיר את הרכיב בזמן שהאנימציה פועלת, אתם יכולים לשנות את shouldKeepEnabledForOngoingAnimation בממשק SharedContentConfig כדי להחזיר ערך false.
דילוג לפריסה הסופית
כברירת מחדל, כשעוברים בין שני פריסות, גודל הפריסה משתנה באנימציה בין מצב ההתחלה למצב הסיום. יכול להיות שההתנהגות הזו לא רצויה כשמוסיפים אנימציה לתוכן כמו טקסט.
בדוגמה הבאה, טקסט התיאור "Lorem Ipsum" נכנס למסך בשתי דרכים שונות. בדוגמה הראשונה, הטקסט משתנה כשהוא נכנס, כי הקונטיינר גדל. בדוגמה השנייה, הטקסט לא משתנה כשהוא גדל. הוספת Modifier.skipToLookaheadSize() מונעת את הזרימה מחדש כשהוא גדל.
אין |
|
|---|---|
קליפים ושכבות-על
כדי שרכיבים משותפים ישותפו בין פונקציות קומפוזביליות שונות, הרינדור של הפונקציה הקומפוזבילית מועלה לשכבת-על כשהמעבר מתחיל להתאים ליעד שלו. ההשפעה של זה היא שהיא תצא מהגבולות של ההורה ומהטרנספורמציות של השכבה שלו (לדוגמה, אלפא וקנה מידה).
הוא יוצג מעל רכיבים אחרים בממשק המשתמש שלא משותפים. בסיום המעבר, הרכיב יוסר מהשכבה ויועבר ל-DrawScope משלו.
כדי לחתוך רכיב משותף לצורה, משתמשים בפונקציה הרגילה Modifier.clip(). צריך להציב אותו אחרי sharedElement():
Image( painter = painterResource(id = R.drawable.cupcake), contentDescription = "Cupcake", modifier = Modifier .size(100.dp) .sharedElement( rememberSharedContentState(key = "image"), animatedVisibilityScope = this@AnimatedContent ) .clip(RoundedCornerShape(16.dp)), contentScale = ContentScale.Crop )
אם אתם רוצים לוודא שרכיב משותף אף פעם לא יוצג מחוץ לקונטיינר הורה, אתם יכולים להגדיר את clipInOverlayDuringTransition ב-sharedElement(). כברירת מחדל, בגבולות משותפים בתצוגות עץ, clipInOverlayDuringTransition משתמש בנתיב החיתוך של ההורה sharedBounds().
כדי לתמוך בשמירה על רכיבים ספציפיים בממשק המשתמש, כמו סרגל תחתון או כפתור פעולה צף, תמיד בחלק העליון במהלך מעבר של רכיב משותף, משתמשים ב-Modifier.renderInSharedTransitionScopeOverlay(). כברירת מחדל, המשנה הזה שומר את התוכן בשכבת-העל בזמן שהמעבר המשותף פעיל.
לדוגמה, ב-Jetsnack, צריך להציב את BottomAppBar מעל הרכיב המשותף עד שהמסך לא יהיה גלוי. הוספת המשתנה לרכיב הקומפוזבילי שומרת על ההבלטה שלו.
בלי |
עם |
|---|---|
יכול להיות שתרצו שהפונקציה הקומפוזבילית הלא משותפת תונפש וגם תישאר מעל הפונקציות הקומפוזביליות האחרות לפני המעבר. במקרים כאלה, משתמשים ב-renderInSharedTransitionScopeOverlay().animateEnterExit() כדי להוסיף אנימציה לפונקציה הקומפוזבילית בזמן שהמעבר של הרכיב המשותף פועל:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
במקרים הנדירים שבהם אתם לא רוצים שהרכיב המשותף יעובד בשכבת-על, אתם יכולים להגדיר את renderInOverlayDuringTransition ב-sharedElement() כ-false.
הודעה לפריסות אחיות על שינויים בגודל של רכיב משותף
כברירת מחדל, sharedBounds() ו-sharedElement() לא מודיעים למאגר ההורה על שינויים בגודל בזמן המעבר בין הפריסות.
כדי להפיץ את השינויים בגודל למאגר ההורה בזמן המעבר, משנים את הפרמטר placeholderSize ל-PlaceholderSize.AnimatedSize. הפעולה הזו תגרום לפריט לגדול או להתכווץ. כל שאר הפריטים בפריסה מגיבים לשינוי.
|
(שימו לב איך הפריטים האחרים ברשימה זזים למטה בתגובה להגדלת הפריט האחד) |
|---|---|