הצגת שינויים בפריסה באמצעות מעבר

כדאי לנסות את הדרך של Compose
‫Jetpack Compose היא ערכת הכלים המומלצת לבניית ממשק משתמש ל-Android. איך משתמשים באנימציות בכתיבת אימייל

מסגרת המעברים של Android מאפשרת להוסיף אנימציה לכל סוגי התנועה בממשק המשתמש על ידי אספקת פריסות ההתחלה והסיום. אתם יכולים לבחור את סוג האנימציה שאתם רוצים – למשל, להוסיף אפקט של הופעה או היעלמות של התצוגות, או לשנות את גודל התצוגות – ומסגרת המעבר קובעת איך ליצור את האנימציה מפריסת ההתחלה לפריסת הסיום.

מסגרת המעבר כוללת את התכונות הבאות:

  • אנימציות ברמת הקבוצה: החלת אפקטים של אנימציה על כל התצוגות בהיררכיית תצוגות.
  • אנימציות מובנות: אפשר להשתמש באנימציות מוגדרות מראש לאפקטים נפוצים כמו דהייה או תנועה.
  • תמיכה בקובצי משאבים: טעינה של היררכיות תצוגות ואנימציות מובנות מקובצי משאבי פריסה.
  • קריאות חוזרות (callback) של מחזור החיים: מקבלים קריאות חוזרות שמאפשרות לשלוט באנימציה ובתהליך השינוי של ההיררכיה.

התהליך הבסיסי ליצירת אנימציה בין שני פריסות הוא כזה:

  1. יוצרים אובייקט Scene עבור פריסות ההתחלה והסיום. עם זאת, הסצנה בפריסה הראשונית נקבעת לרוב באופן אוטומטי מהפריסה הנוכחית.
  2. יוצרים אובייקט Transition כדי להגדיר את סוג האנימציה הרצוי.
  3. מתקשרים TransitionManager.go(), והמערכת מפעילה את האנימציה כדי להחליף את הפריסות.

הדיאגרמה באיור 1 ממחישה את הקשר בין הפריסות, הסצנות, המעבר והאנימציה הסופית.

איור 1. איור בסיסי של האופן שבו מסגרת המעברים יוצרת אנימציה.

יצירת סצנה

סצנות שומרות את המצב של היררכיית תצוגות, כולל כל התצוגות וערכי המאפיינים שלהן. מסגרת המעברים יכולה להריץ אנימציות בין סצנת התחלה לסצנת סיום.

אפשר ליצור את הסצנות מקובץ משאבים של פריסה או מקבוצה של תצוגות בקוד. עם זאת, סצנת ההתחלה של המעבר נקבעת לרוב באופן אוטומטי מתוך ממשק המשתמש הנוכחי.

סצנה יכולה גם להגדיר פעולות משלה שמופעלות כשמבצעים שינוי בסצנה. התכונה הזו שימושית לניקוי הגדרות התצוגה אחרי המעבר לסצנה.

יצירת סצנה ממשאב פריסה

אפשר ליצור מופע Scene ישירות מקובץ של משאב פריסה. כדאי להשתמש בטכניקה הזו כשהיררכיית התצוגות בקובץ היא בעיקר סטטית. הסצנה שמתקבלת מייצגת את המצב של היררכיית התצוגות בזמן שיצרתם את מופע Scene. אם משנים את היררכיית התצוגה, צריך ליצור מחדש את הסצנה. המסגרת יוצרת את הסצנה מהיררכיית התצוגה המלאה בקובץ. אי אפשר ליצור סצנה מחלק מקובץ פריסה.

כדי ליצור מופע Scene מקובץ משאב פריסה, מאחזרים את שורש הסצנה מהפריסה כ-ViewGroup. לאחר מכן, קוראים לפונקציה Scene.getSceneForLayout() עם שורש הסצנה ומזהה המשאב של קובץ הפריסה שמכיל את היררכיית התצוגה של הסצנה.

הגדרת פריסות לסצנות

בקטעי הקוד שבהמשך הסעיף מוצגות דוגמאות ליצירת שני סצנות שונות עם אותו רכיב בסיס של סצנה. בקטעי הקוד אפשר לראות גם שאפשר לטעון כמה אובייקטים של Scene שלא קשורים זה לזה, בלי שיהיה קשר ביניהם.

הדוגמה מורכבת מהגדרות הפריסה הבאות:

  • הפריסה הראשית של פעילות עם תווית טקסט וילד FrameLayout.
  • ConstraintLayout לסצנה הראשונה עם שני שדות טקסט.
  • ConstraintLayout לסצנה השנייה עם אותם שני שדות טקסט בסדר שונה.

הדוגמה מתוכננת כך שכל האנימציה מתרחשת בפריסת הצאצא של הפריסה הראשית של הפעילות. תווית הטקסט בפריסה הראשית נשארת סטטית.

הפריסה העיקרית של הפעילות מוגדרת כך:

res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/master_layout">
    <TextView
        android:id="@+id/title"
        ...
        android:text="Title"/>
    <FrameLayout
        android:id="@+id/scene_root">
        <include layout="@layout/a_scene" />
    </FrameLayout>
</LinearLayout>

הגדרת הפריסה הזו מכילה שדה טקסט ורכיב צאצא FrameLayout עבור רכיב הבסיס של הסצנה. הפריסה של הסצנה הראשונה כלולה בקובץ הפריסה הראשי. כך האפליקציה יכולה להציג אותו כחלק מממשק המשתמש הראשוני וגם לטעון אותו לסצנה, כי אפשר לטעון לסצנה רק קובץ פריסה שלם.

פריסת הסצנה הראשונה מוגדרת כך:

res/layout/a_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/text_view1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
    <TextView
        android:id="@+id/text_view2"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 2"
        app:layout_constraintTop_toBottomOf="@id/text_view1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

הפריסה של הסצנה השנייה מכילה את אותם שני שדות טקסט – עם אותם מזהים – אבל הם ממוקמים בסדר שונה. היא מוגדרת כך:

res/layout/another_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/text_view2"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    <TextView
        android:id="@+id/text_view1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 1"
        app:layout_constraintTop_toBottomOf="@id/text_view2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

יצירת סצנות מפריסות

אחרי שיוצרים הגדרות לשני פריסות האילוצים, אפשר לקבל סצנה לכל אחת מהן. כך תוכלו לעבור בין שני סוגי הממשקים. כדי לקבל סצנה, צריך הפניה לרכיב הבסיסי של הסצנה ולמזהה משאב הפריסה.

בקטע הקוד הבא מוצג איך מקבלים הפניה לרכיב הבסיסי של הסצנה ויוצרים שני אובייקטים של Scene מקובצי הפריסה:

Kotlin

val sceneRoot: ViewGroup = findViewById(R.id.scene_root)
val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this)
val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)

Java

Scene aScene;
Scene anotherScene;

// Create the scene root for the scenes in this app.
sceneRoot = (ViewGroup) findViewById(R.id.scene_root);

// Create the scenes.
aScene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this);
anotherScene =
    Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this);

באפליקציה יש עכשיו שני אובייקטים של Scene שמבוססים על היררכיות של תצוגות. שני הסצנות משתמשות בשורש הסצנה שמוגדר על ידי הרכיב FrameLayout ב-res/layout/activity_main.xml.

יצירת סצנה בקוד

אפשר גם ליצור מופע Scene בקוד מאובייקט ViewGroup. משתמשים בטכניקה הזו כשמשנים את היררכיות התצוגה ישירות בקוד או כשיוצרים אותן באופן דינמי.

כדי ליצור סצנה מהיררכיית תצוגות בקוד, משתמשים בבונה Scene(sceneRoot, viewHierarchy). הפעלת ה-constructor הזה שקולה להפעלת הפונקציה Scene.getSceneForLayout() כשכבר הרחבתם קובץ פריסה.

בקטע הקוד הבא אפשר לראות איך יוצרים מופע Scene מרכיב הבסיס של הסצנה וממה שמוצג בהיררכיית תצוגות של הסצנה בקוד:

Kotlin

val sceneRoot = someLayoutElement as ViewGroup
val viewHierarchy = someOtherLayoutElement as ViewGroup
val scene: Scene = Scene(sceneRoot, viewHierarchy)

Java

Scene mScene;

// Obtain the scene root element.
sceneRoot = (ViewGroup) someLayoutElement;

// Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered.
viewHierarchy = (ViewGroup) someOtherLayoutElement;

// Create a scene.
mScene = new Scene(sceneRoot, mViewHierarchy);

יצירת פעולות בסצנה

ה-framework מאפשר להגדיר פעולות מותאמות אישית בסצנה שהמערכת מפעילה כשנכנסים לסצנה או יוצאים ממנה. במקרים רבים, אין צורך להגדיר פעולות מותאמות אישית בסצנה, כי המסגרת מנפישה את השינוי בין הסצנות באופן אוטומטי.

פעולות בסצנה שימושיות במקרים הבאים:

  • להנפיש תצוגות שלא נמצאות באותה היררכיה. אפשר להוסיף אנימציה לתצוגות של סצנות הפתיחה והסיום באמצעות פעולות של יציאה וכניסה לסצנה.
  • כדי להנפיש תצוגות שמסגרת המעברים לא יכולה להנפיש באופן אוטומטי, כמו אובייקטים של ListView. מידע נוסף זמין בקטע בנושא מגבלות.

כדי לספק פעולות מותאמות אישית בסצנה, מגדירים את הפעולות כאובייקטים של Runnable ומעבירים אותם לפונקציות Scene.setExitAction() או Scene.setEnterAction(). המסגרת קוראת לפונקציה setExitAction() בסצנת ההתחלה לפני הפעלת אנימציית המעבר, ולפונקציה setEnterAction() בסצנת הסיום אחרי הפעלת אנימציית המעבר.

החלת מעבר

מסגרת המעבר מייצגת את סגנון האנימציה בין סצנות עם אובייקט Transition. אפשר ליצור מופע של Transition באמצעות מחלקות משנה מובנות, כמו AutoTransition ו-Fade, או להגדיר מעבר משלכם. אחר כך אפשר להריץ את האנימציה בין הסצנות על ידי העברת נקודת הסיום Scene והנקודה Transition אל TransitionManager.go().

מחזור החיים של המעבר דומה למחזור החיים של הפעילות, והוא מייצג את מצבי המעבר שהמסגרת עוקבת אחריהם בין ההתחלה לסיום של אנימציה. במצבים חשובים במחזור החיים, המסגרת מפעילה פונקציות של קריאה חוזרת שאפשר להטמיע כדי להתאים את ממשק המשתמש בשלבים שונים של המעבר.

יצירת מעבר

בקטע הקודם הוסבר איך ליצור סצנות שמייצגות את המצב של היררכיות שונות של תצוגות. אחרי שמגדירים את סצנות ההתחלה והסיום שרוצים לעבור ביניהן, יוצרים אובייקט Transition שמגדיר אנימציה. המסגרת מאפשרת לציין מעבר מובנה בקובץ משאבים ולהרחיב אותו בקוד, או ליצור מופע של מעבר מובנה ישירות בקוד.

טבלה 1. סוגי מעברים מובנים.

דרגה תג אפקט
AutoTransition <autoTransition/> מעבר ברירת מחדל. התצוגות דוהות, זזות ומשנות את הגודל, ואז דוהות פנימה, לפי הסדר הזה.
ChangeBounds <changeBounds/> העברה ושינוי גודל של תצוגות.
ChangeClipBounds <changeClipBounds/> האפקט מתעד את View.getClipBounds() לפני השינוי בסצנה ואחריו, ומנפיש את השינויים האלה במהלך המעבר.
ChangeImageTransform <changeImageTransform/> האפקט מצלם את המטריצה של ImageView לפני ואחרי שינוי הסצנה ומנפיש אותה במהלך המעבר.
ChangeScroll <changeScroll/> הצומת הזה מתעד את מאפייני הגלילה של היעדים לפני ואחרי השינוי בסצנה, ומנפיש את השינויים.
ChangeTransform <changeTransform/> מצלם את הגודל והסיבוב של התצוגות לפני ואחרי שינוי הסצנה ומנפיש את השינויים האלה במהלך המעבר.
Explode <explode/> הוא עוקב אחרי שינויים בחשיפה של תצוגות היעד בסצנות ההתחלה והסיום, ומזיז את התצוגות פנימה או החוצה מהקצוות של הסצנה.
Fade <fade/> fade_in מופיע בהדרגה בצפיות.
fade_out מציג את התצוגות בצורה שקופה יותר.‫
fade_in_out (ברירת מחדל) מבצע fade_out ואחריו fade_in.
Slide <slide/> עוקב אחרי שינויים בחשיפה של תצוגות יעד בסצנות ההתחלה והסיום ומזיז תצוגות פנימה או החוצה מאחת הקצוות של הסצנה.

יצירת מופע של מעבר מקובץ משאבים

הטכניקה הזו מאפשרת לשנות את הגדרת המעבר בלי לשנות את הקוד של הפעילות. הטכניקה הזו שימושית גם להפרדה בין הגדרות מורכבות של מעברים לבין קוד האפליקציה, כמו שמוסבר בקטע בנושא הגדרת מעברים מרובים.

כדי לציין מעבר מובנה בקובץ משאבים, פועלים לפי השלבים הבאים:

  • מוסיפים את הספרייה res/transition/ לפרויקט.
  • יוצרים קובץ משאבי XML חדש בתוך הספרייה הזו.
  • מוסיפים צומת XML לאחד מהמעברים המובנים.

לדוגמה, קובץ המשאבים הבא מציין את המעבר Fade:

res/transition/fade_transition.xml

<fade xmlns:android="http://schemas.android.com/apk/res/android" />

קטע הקוד הבא מראה איך להרחיב מופע של Transition בתוך פעילות מקובץ משאבים:

Kotlin

var fadeTransition: Transition =
    TransitionInflater.from(this)
                      .inflateTransition(R.transition.fade_transition)

Java

Transition fadeTransition =
        TransitionInflater.from(this).
        inflateTransition(R.transition.fade_transition);

יצירת מופע של מעבר בקוד

הטכניקה הזו שימושית ליצירת אובייקטים של מעברים באופן דינמי אם משנים את ממשק המשתמש בקוד, וליצירת מופעים פשוטים של מעברים מובנים עם מעט פרמטרים או ללא פרמטרים בכלל.

כדי ליצור מופע של מעבר מובנה, מפעילים אחד מהבנאים הציבוריים במחלקות המשנה של המחלקה Transition. לדוגמה, קטע הקוד הבא יוצר מופע של המעבר Fade:

Kotlin

var fadeTransition: Transition = Fade()

Java

Transition fadeTransition = new Fade();

החלת מעבר

בדרך כלל משתמשים במעבר כדי לשנות בין היררכיות שונות של תצוגות בתגובה לאירוע, כמו פעולת משתמש. לדוגמה, באפליקציית חיפוש: כשמשתמש מזין מונח חיפוש ומקיש על לחצן החיפוש, האפליקציה משתנה לסצנה שמייצגת את פריסת התוצאות, תוך שימוש במעבר שגורם ללחצן החיפוש להיעלם בהדרגה ולתוצאות החיפוש להופיע בהדרגה.

כדי לבצע שינוי בסצנה תוך החלת מעבר בתגובה לאירוע בפעילות, קוראים לפונקציית המחלקה TransitionManager.go() עם סצנת הסיום ומופע המעבר שבו רוצים להשתמש לאנימציה, כמו שמוצג בקטע הקוד הבא:

Kotlin

TransitionManager.go(endingScene, fadeTransition)

Java

TransitionManager.go(endingScene, fadeTransition);

המסגרת משנה את ההיררכיה של התצוגה בתוך שורש הסצנה עם ההיררכיה של התצוגה מהסצנה הסופית בזמן הפעלת האנימציה שצוינה על ידי מופע המעבר. הסצנה הראשונה היא הסצנה האחרונה מהמעבר הקודם. אם אין מעבר קודם, סצנת ההתחלה נקבעת אוטומטית מהמצב הנוכחי של ממשק המשתמש.

אם לא מציינים מופע של מעבר, מנהל המעברים יכול להחיל מעבר אוטומטי שעושה משהו סביר ברוב המצבים. למידע נוסף, אפשר לעיין בהפניית ה-API של המחלקה TransitionManager.

בחירת צפיות ספציפיות במוצר

מסגרת העבודה מחילה מעברים על כל התצוגות בסצנות ההתחלה והסיום כברירת מחדל. במקרים מסוימים, יכול להיות שתרצו להחיל אנימציה רק על חלק מהתצוגות בסצנה. המסגרת מאפשרת לכם לבחור תצוגות ספציפיות שאתם רוצים להנפיש. לדוגמה, המסגרת לא תומכת באנימציה של שינויים באובייקטים מסוג ListView, ולכן לא כדאי לנסות להוסיף להם אנימציה במהלך מעבר.

כל תצוגה שהאנימציה עוברת אליה נקראת יעד. אפשר לבחור רק יעדים שמהווים חלק מהיררכיית התצוגה שמשויכת לסצנה.

כדי להסיר תצוגה אחת או יותר מרשימת היעדים, צריך לבצע קריאה ל-method‏ removeTarget() לפני שמתחילים את המעבר. כדי להוסיף לרשימת היעדים רק את התצוגות המפורטות שציינתם, קוראים לפונקציה addTarget(). מידע נוסף זמין במאמר בנושא הפניית API למחלקה Transition.

ציון של כמה מעברים

כדי להפיק את המרב מאנימציה, צריך להתאים אותה לסוג השינויים שמתרחשים בין הסצנות. לדוגמה, אם מסירים חלק מהתצוגות ומוסיפים אחרות בין הסצנות, אנימציית הדהייה פנימה או החוצה מספקת אינדיקציה ברורה לכך שחלק מהתצוגות כבר לא זמינות. אם מעבירים תצוגות לנקודות שונות במסך, כדאי להוסיף אנימציה לתנועה כדי שהמשתמשים ישימו לב למיקום החדש של התצוגות.

אתם לא חייבים לבחור רק אנימציה אחת, כי מסגרת המעברים מאפשרת לכם לשלב אפקטים של אנימציה בסט מעברים שמכיל קבוצה של מעברים מובנים או מותאמים אישית.

כדי להגדיר קבוצת מעברים מתוך אוסף של מעברים ב-XML, יוצרים קובץ משאבים בספרייה res/transitions/ ומפרטים את המעברים מתחת לרכיב TransitionSet. לדוגמה, בקטע הקוד הבא אפשר לראות איך מציינים קבוצת מעברים עם התנהגות זהה למחלקה AutoTransition:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade android:fadingMode="fade_out" />
    <changeBounds />
    <fade android:fadingMode="fade_in" />
</transitionSet>

כדי להרחיב את קבוצת המעברים לאובייקט TransitionSet בקוד, קוראים לפונקציה TransitionInflater.from() בפעילות. הכיתה TransitionSet היא הרחבה של הכיתה Transition, כך שאפשר להשתמש בה עם מנהל מעברים בדיוק כמו בכל מופע אחר של Transition.

הוספת מעבר בלי סצנות

שינוי היררכיות התצוגה הוא לא הדרך היחידה לשנות את ממשק המשתמש. אפשר גם להוסיף, לשנות ולהסיר תצוגות צאצא בהיררכיה הנוכחית.

לדוגמה, אפשר להטמיע אינטראקציה עם חיפוש בפריסה אחת. מתחילים עם הפריסה שבה מוצג שדה להזנת חיפוש וסמל חיפוש. כדי לשנות את ממשק המשתמש כך שיוצגו התוצאות, צריך להסיר את לחצן החיפוש כשמשתמש מקיש עליו על ידי קריאה לפונקציה ViewGroup.removeView() ולהוסיף את תוצאות החיפוש על ידי קריאה לפונקציה ViewGroup.addView().

אפשר להשתמש בגישה הזו אם האפשרות האחרת היא ליצור שתי היררכיות כמעט זהות. במקום ליצור ולתחזק שני קובצי פריסה נפרדים בשביל הבדל קטן בממשק המשתמש, אפשר להשתמש בקובץ פריסה אחד שמכיל היררכיית תצוגות שמשנים בקוד.

אם מבצעים שינויים בהיררכיית התצוגה הנוכחית בדרך הזו, לא צריך ליצור סצנה. במקום זאת, אפשר ליצור ולהחיל מעבר בין שני מצבים של היררכיית תצוגה באמצעות מעבר מושהה. התכונה הזו של מסגרת המעברים מתחילה במצב הנוכחי של היררכיית התצוגה, מתעדת את השינויים שאתם מבצעים בתצוגות שלה ומחיל מעבר שמציג את השינויים באנימציה כשהמערכת מציירת מחדש את ממשק המשתמש.

כדי ליצור מעבר מושהה בהיררכיית תצוגה יחידה, מבצעים את השלבים הבאים:

  1. כשמתרחש האירוע שמפעיל את המעבר, קוראים לפונקציה TransitionManager.beginDelayedTransition() ומספקים את תצוגת האב של כל התצוגות שרוצים לשנות ואת המעבר שרוצים להשתמש בו. במסגרת מאוחסן המצב הנוכחי של תצוגות הצאצאים וערכי המאפיינים שלהן.
  2. מבצעים שינויים בתצוגות המפורטות של הילדים לפי הצורך בתרחיש השימוש. המסגרת מתעדת את השינויים שאתם מבצעים בתצוגות המשניות ובנכסים שלהן.
  3. כשהמערכת מציירת מחדש את ממשק המשתמש בהתאם לשינויים שביצעתם, המסגרת מנפישה את השינויים בין המצב המקורי למצב החדש.

בדוגמה הבאה מוצג איך להוסיף אנימציה למעבר של תצוגת טקסט להיררכיית תצוגות באמצעות מעבר מושהה. בקטע הקוד הראשון מוצג קובץ הגדרת הפריסה:

res/layout/activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mainLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <EditText
        android:id="@+id/inputText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    ...
</androidx.constraintlayout.widget.ConstraintLayout>

בקטע הקוד הבא מוצג הקוד שמפעיל את האנימציה של הוספת תצוגת הטקסט:

MainActivity

Kotlin

setContentView(R.layout.activity_main)
val labelText = TextView(this).apply {
    text = "Label"
    id = R.id.text
}
val rootView: ViewGroup = findViewById(R.id.mainLayout)
val mFade: Fade = Fade(Fade.IN)
TransitionManager.beginDelayedTransition(rootView, mFade)
rootView.addView(labelText)

Java

private TextView labelText;
private Fade mFade;
private ViewGroup rootView;
...
// Load the layout.
setContentView(R.layout.activity_main);
...
// Create a new TextView and set some View properties.
labelText = new TextView(this);
labelText.setText("Label");
labelText.setId(R.id.text);

// Get the root view and create a transition.
rootView = (ViewGroup) findViewById(R.id.mainLayout);
mFade = new Fade(Fade.IN);

// Start recording changes to the view hierarchy.
TransitionManager.beginDelayedTransition(rootView, mFade);

// Add the new TextView to the view hierarchy.
rootView.addView(labelText);

// When the system redraws the screen to show this update,
// the framework animates the addition as a fade in.

הגדרה של קריאות חוזרות (callback) למחזור החיים של המעבר

מחזור החיים של המעבר דומה למחזור החיים של הפעילות. הוא מייצג את מצבי המעבר שהמסגרת עוקבת אחריהם במהלך התקופה שבין הקריאה לפונקציה TransitionManager.go() לבין השלמת האנימציה. במצבים חשובים במחזור החיים, המסגרת מפעילה קריאות חוזרות (callback) שמוגדרות על ידי הממשק TransitionListener.

התקשרות חוזרת (callback) של מחזור החיים של המעבר שימושית, למשל, להעתקת ערך של מאפיין תצוגה מההיררכיה של תצוגת ההתחלה להיררכיה של תצוגת הסיום במהלך שינוי סצנה. אי אפשר פשוט להעתיק את הערך מתצוגת ההתחלה שלו לתצוגה בהיררכיית תצוגת הסיום, כי היררכיית תצוגת הסיום לא מורחבת עד שהמעבר מסתיים. במקום זאת, צריך לאחסן את הערך במשתנה ואז להעתיק אותו להיררכיית התצוגה הסופית כשהמסגרת מסיימת את המעבר. כדי לקבל הודעה כשהמעבר יסתיים, צריך להטמיע את הפונקציה TransitionListener.onTransitionEnd() בפעילות.

מידע נוסף זמין במאמר בנושא הפניה ל-API של המחלקה TransitionListener.

מגבלות

בקטע הזה מפורטות כמה מגבלות ידועות של מסגרת המעברים:

  • יכול להיות שאנימציות שמוחלות על תג SurfaceView לא יוצגו בצורה תקינה. ‫SurfaceView instances מתעדכנים משרשור שאינו שרשור של ממשק משתמש, ולכן יכול להיות שהעדכונים לא יסתנכרנו עם האנימציות של תצוגות אחרות.
  • יכול להיות שסוגים מסוימים של מעברים לא ייצרו את אפקט האנימציה הרצוי כשמחילים אותם על TextureView.
  • שיעורים שמרחיבים את AdapterView, כמו ListView, מנהלים את תצוגות הצאצא שלהם בדרכים שלא תואמות למסגרת המעברים. אם מנסים להנפיש תצוגה על סמך AdapterView, יכול להיות שהתצוגה במכשיר תפסיק להגיב.
  • אם מנסים לשנות את הגודל של TextView עם אנימציה, הטקסט קופץ למיקום חדש לפני שהגודל של האובייקט משתנה לגמרי. כדי להימנע מהבעיה הזו, אל תשתמשו באנימציה כדי לשנות את הגודל של תצוגות שמכילות טקסט.