1. מבוא
Material Design היא מערכת ליצירת מוצרים דיגיטליים יפים ונועזים. שילוב של סגנון, מיתוג, אינטראקציה ותנועה בקבוצה עקבית של עקרונות ורכיבים מאפשר לצוותים של מוצרים לממש את מלוא הפוטנציאל שלהם בתכנון.
Material Components (MDC) עוזרים למפתחים להטמיע את Material Design. MDC נוצר על ידי צוות של מהנדסים ומעצבי חוויית משתמש ב-Google, והוא כולל עשרות רכיבי ממשק משתמש יפים ופונקציונליים. הוא זמין ל-Android, ל-iOS, לאינטרנט ול-Flutter.material.io/develop |
מהי מערכת התנועה של Material ל-Android?
מערכת התנועה של Material ל-Android היא קבוצה של דפוסי מעבר בספריית MDC-Android שיכולים לעזור למשתמשים להבין את האפליקציה ולנווט בה, כפי שמתואר בהנחיות של Material Design.
ארבעת הדפוסים העיקריים של מעברים ב-Material הם:
- טרנספורמציה של קונטיינר: מעברים בין רכיבי ממשק משתמש שמכילים קונטיינר. הדפוס הזה יוצר חיבור גלוי בין שני רכיבי ממשק משתמש נפרדים על ידי טרנספורמציה חלקה של רכיב אחד לרכיב אחר.
- ציר משותף: מעבר בין רכיבי ממשק משתמש שיש להם קשר מרחבי או ניווט. המערכת משתמשת בטרנספורמציה משותפת על ציר ה-x, ה-y או ה-z כדי לחזק את הקשר בין הרכיבים.
- התחזקות הדרגתית: מעברים בין רכיבי ממשק משתמש שאין ביניהם קשר חזק. הדפוס הזה משתמש בהתחזקות הדרגתית החוצה והתחזקות הדרגתית פנימה, עם שינוי קנה המידה של הרכיב הנכנס.
- עמעום: משמש לרכיבים בממשק המשתמש שנכנסים לגבולות המסך או יוצאים מהם.
ספריית MDC-Android מציעה סיווגי מעבר לדפוסים האלה, שמבוססים על ספריית המעבר של AndroidX (androidx.transition
) וגם על מסגרת המעבר של Android (android.transition
):
AndroidX
- זמין בחבילה
com.google.android.material.transition
- תמיכה ברמת API 14 ואילך
- תמיכה בקטעים ובתצוגות, אבל לא בפעילויות או בחלונות
- מכיל תיקוני באגים שהועברו לאחור והתנהגות עקבית ברמות API שונות
Framework
- זמין בחבילה של
com.google.android.material.transition.platform
- תמיכה ברמת API 21 ואילך
- תמיכה בקטעים, בתצוגות, בפעילויות ובחלונות
- תיקוני באגים שלא הועברו לאחור ויכול להיות שאופן הפעולה שלהם יהיה שונה ברמות ה-API
ב-codelab הזה נשתמש במעברים של Material שנבנו על גבי ספריית AndroidX, כלומר נתמקד בעיקר ב-Fragments וב-Views.
מה תפַתחו
בקודלאב הזה תלמדו איך ליצור כמה מעברים באפליקציית אימייל לדוגמה ל-Android שנקראת Reply, באמצעות Kotlin. כך תוכלו להבין איך להשתמש במעברים מ-MDC-Android כדי להתאים אישית את המראה והתחושה של האפליקציה.
קוד ההתחלה לאפליקציית ה-Reply יסופק, וישלבו את המעברים הבאים ב-Material באפליקציה. את המעברים הבאים ניתן לראות בקובץ ה-GIF המלא של Codelab:
- מעבר של Container Transform מרשימת כתובות האימייל לדף הפרטים של האימייל
- מעבר של טרנספורמציה של קונטיינר מלחצן FAB לדף כתיבת אימייל
- מעבר ציר ה-Z המשותף מסמל החיפוש לדף הצפייה בחיפוש
- מעבר מסוג Fade Through בין דפי תיבת הדואר
- מעבר של Container Transform מצ'יפ של כתובת אימייל לתצוגת כרטיס
מה צריך להכין
- ידע בסיסי בפיתוח Android וב-Kotlin
- Android Studio (אם עדיין לא עשיתם זאת, אתם יכולים להוריד את התוכנה כאן)
- אמולטור או מכשיר של Android (האפשרות זמינה ב-Android Studio)
- קוד לדוגמה (ראו שלב הבא)
מה מידת הניסיון שלך בפיתוח אפליקציות ל-Android?
2. הגדרת סביבת הפיתוח
הפעלת Android Studio
כשפותחים את Android Studio, אמור להופיע חלון עם הכיתוב 'Welcome to Android Studio' (ברוכים הבאים ל-Android Studio). עם זאת, אם זו הפעם הראשונה שאתם מריצים את Android Studio, עליכם לבצע את השלבים של אשף ההגדרה של Android Studio עם ערכי ברירת המחדל. ייתכן שתהליך ההורדה וההתקנה של הקבצים הדרושים יימשך מספר דקות, לכן ניתן להשאיר את הקובץ פועל ברקע בזמן ביצוע הקטע הבא.
אפשרות 1: שכפול אפליקציית Codelab למתחילים מ-GitHub
כדי לשכפל את codelab הזה מ-GitHub, מריצים את הפקודות הבאות:
git clone https://github.com/material-components/material-components-android-motion-codelab.git cd material-components-android-motion-codelab
אפשרות 2: מורידים את קובץ ה-ZIP של אפליקציית Codelab למתחילים
האפליקציה לתחילת הפעולה נמצאת בספרייה material-components-android-motion-codelab-develop
.
טעינה של קוד ההתחלה ב-Android Studio
- כשאשף ההגדרה יסתיים ובחלון ברוכים הבאים אל Android Studio, לוחצים על פתיחת פרויקט קיים של Android Studio.
- עוברים אל הספרייה שבה התקנתם את הקוד לדוגמה ובוחרים את הספרייה לדוגמה כדי לפתוח את הפרויקט.
- ממתינים רגע עד שמערכת Android Studio תסיים לבנות ולסנכרן את הפרויקט, כפי שמוצג באינדיקטורים של הפעילות בחלק התחתון של החלון של Android Studio.
- בשלב הזה, ייתכן שיוצגו ב-Android Studio חלק משגיאות ה-build כי ה-SDK של Android או כלי ה-build חסרים לכם, כמו זה שמוצג למטה. כדי להתקין או לעדכן אותם ולסנכרן את הפרויקט, פועלים לפי ההוראות ב-Android Studio. אם הבעיות נמשכות, יש לפעול לפי המדריך לעדכון הכלים באמצעות SDK Manager.
אימות יחסי התלות של פרויקטים
הפרויקט צריך להיות תלוי בספריית MDC-Android. הקוד לדוגמה שהורדתם כבר אמור לכלול את התלות הזאת, אבל בואו נבחן את ההגדרות כדי לוודא זאת.
עוברים לקובץ build.gradle
של המודול app
ומוודאים שהבלוק dependencies
כולל תלות ב-MDC-Android:
implementation 'com.google.android.material:material:1.2.0'
הפעלת אפליקציה לתחילת פעולה
- צריך לוודא שתצורת ה-build שמימין לאפשרות המכשיר היא
app
. - לוחצים על לחצן ההפעלה / ההפעלה כדי לבנות את האפליקציה ולהפעיל אותה.
- בחלון בחירת יעד פריסה, אם כבר יש לכם מכשיר Android שרשום ברשימת המכשירים הזמינים, מדלגים לשלב 8. אחרת, לוחצים על יצירת מכשיר וירטואלי חדש.
- במסך Select Hardware (בחירת חומרה), בוחרים מכשיר טלפון, כמו Pixel 3, ולוחצים על Next (הבא).
- במסך System Image, בוחרים גרסת Android עדכנית, רצוי ברמת ה-API הגבוהה ביותר. אם היא לא מותקנת, לוחצים על הקישור הורדה שמופיע ומשלימים את ההורדה.
- לוחצים על הבא.
- במסך מכשיר וירטואלי של Android (AVD), משאירים את ההגדרות כפי שהן ולוחצים על סיום.
- בוחרים מכשיר Android מתיבת הדו-שיח של יעד הפריסה.
- לוחצים על אישור.
- Android Studio יוצר את האפליקציה, פורס אותה ופותח אותה באופן אוטומטי במכשיר היעד.
הצלחת! קוד הסימן לתחילת הפעולה בדף הבית של התשובה אמור לפעול באמולטור שלכם. אמורה להופיע תיבת הדואר הנכנס עם רשימה של הודעות אימייל.
אופציונלי: האטת האנימציות במכשיר
מאחר שה-Codelab הזה כולל מעברים מהירים אך מלוטשים, כדאי להאט את האנימציות במכשיר כדי לצפות בחלק מהפרטים המדויקים יותר של המעברים בזמן ההטמעה. אפשר לעשות זאת באמצעות פקודות מעטפת adb
או לחצן ב'הגדרות מהירות'. שימו לב שהשיטות האלה להאטת האנימציות במכשיר ישפיעו גם על האנימציות במכשיר מחוץ לאפליקציית 'תשובה'.
שיטה 1: פקודות ADB Shell
כדי להאט את האנימציות במכשיר פי 10, אפשר להריץ את הפקודות הבאות משורת הפקודה:
adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10
כדי לאפס את מהירות האנימציה במכשיר למהירות הרגילה, מריצים את הפקודות הבאות:
adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1
שיטה 2: לחצן ב'הגדרות מהירות'
לחלופין, כדי להגדיר את הכרטיס 'הגדרות מהירות', צריך להפעיל קודם את הגדרות המפתחים במכשיר, אם עוד לא עשיתם זאת:
- פתיחת האפליקציה 'הגדרות' במכשיר
- גוללים לתחתית הדף ולוחצים על 'מידע על המכשיר המאומלל'.
- גוללים למטה לחלק התחתון ולוחצים במהירות על 'מספר Build' עד שהאפשרות 'הגדרות למפתחים' מופעלת.
לאחר מכן, עדיין באפליקציית 'הגדרות' של המכשיר, מבצעים את הפעולות הבאות כדי להפעיל את המשבצת של ההגדרות המהירות:
- לוחצים על סמל החיפוש או על סרגל החיפוש בחלק העליון של המסך.
- מקלידים 'משבצות' בשדה החיפוש.
- לוחצים על השורה 'כרטיסי מידע למפתחים בהגדרות המהירות'.
- לוחצים על המתג 'קנה מידה של אנימציית חלון'
לסיום, במהלך הקודלאב, תוכלו לפתוח את לוח ההתראות של המערכת מהחלק העליון של המסך ולהשתמש בסמל כדי לעבור בין אנימציות בקצב איטי לבין אנימציות בקצב רגיל.
3. מעיינים בקוד לדוגמה של האפליקציה
בואו נסתכל על הקוד. הכנו אפליקציה שמשתמשת בספרייה של רכיב הניווט של Jetpack כדי לנווט בין כמה קטעי Fragment שונים, והכול בתוך פעילות אחת, MainActivity:
- HomeFragment: הצגת רשימת אימיילים
- EmailFragment: מציג הודעת אימייל מלאה אחת
- ComposeFragment: מאפשרת לכתוב אימייל חדש
- SearchFragment: הצגה של תצוגת חיפוש
navigation_graph.xml
קודם כול, כדי להבין איך מוגדר תרשים הניווט של האפליקציה, אפשר לפתוח את navigation_graph.xml
בספרייה app -> src -> main -> res -> navigation
:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.materialstudies.reply.ui.home.HomeFragment"
android:label="HomeFragment">
<argument...>
<action
android:id="@+id/action_homeFragment_to_emailFragment"
app:destination="@id/emailFragment" />
</fragment>
<fragment
android:id="@+id/emailFragment"
android:name="com.materialstudies.reply.ui.email.EmailFragment"
android:label="EmailFragment">
<argument...>
</fragment>
<fragment
android:id="@+id/composeFragment"
android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
android:label="ComposeFragment">
<argument...>
</fragment>
<fragment
android:id="@+id/searchFragment"
android:name="com.materialstudies.reply.ui.search.SearchFragment"
android:label="SearchFragment" />
<action
android:id="@+id/action_global_homeFragment"
app:destination="@+id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="@+id/navigation_graph"
app:popUpToInclusive="true"/>
<action
android:id="@+id/action_global_composeFragment"
app:destination="@+id/composeFragment" />
<action
android:id="@+id/action_global_searchFragment"
app:destination="@+id/searchFragment" />
</navigation>
כדאי לשים לב איך נמצאים כל המקטעים שהוזכרו למעלה, כאשר מקטע ההשקה שמוגדר כברירת מחדל מוגדר ל-HomeFragment
דרך app:startDestination="@id/homeFragment"
. הגדרת ה-XML הזו של תרשים היעד של הקטעים, יחד עם הפעולות, מספקת מידע לקוד הניווט שנוצר ב-Kotlin, שתראו כשתחברו את המעברים.
activity_main.xml
בשלב הבא, בודקים את הפריסה של activity_main.xml
בספרייה app -> src -> main -> res -> layout
. ה-NavHostFragment
שמוגדר עם תרשים הניווט שלמעלה יוצג:
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation_graph"/>
NavHostFragment
זה ממלא את המסך ומטפל בכל השינויים בניווט במקטעים במסך מלא באפליקציה. ה-BottomAppBar
וה-FloatingActionButton
המעוגנים שלו, גם ב-activity_main.xml
, מוצבים מעל המקטע הנוכחי שמוצג על ידי NavHostFragment
, ולכן יוצגו או יוסתרו בהתאם ליעד המקטע באמצעות קוד האפליקציה לדוגמה שסופק.
בנוסף, הסמל BottomNavDrawerFragment
ב-activity_main.xml
הוא חלונית תחתונה שמכילה תפריט לניווט בין תיבת הדואר הנכנס של כתובות האימייל השונות. התפריט מוצג באופן מותנה באמצעות לחצן הלוגו של התשובה BottomAppBar
.
MainActivity.kt
לסיום, כדי לראות דוגמה לפעולה של ניווט בשימוש, פותחים את MainActivity.kt
בספרייה app -> src -> main -> java -> com.materialstudies.reply.ui
. מאתרים את הפונקציה navigateToSearch()
, שאמורה להיראות כך:
private fun navigateToSearch() {
val directions = SearchFragmentDirections.actionGlobalSearchFragment()
findNavController(R.id.nav_host_fragment).navigate(directions)
}
כך אפשר לנווט לדף של תצוגת החיפוש, בלי מעבר מותאם אישית. במהלך ה-Codelab הזה, תעמקו בפעילות MainActivity ובארבעה מקטעים עיקריים כדי להגדיר מעברי Material שפועלים במקביל לפעולות הניווט השונות באפליקציה.
עכשיו, אחרי שקראתם את הקוד לתחילת העבודה, ניישם את המעבר הראשון.
4. הוספת מעבר של Container Transform מרשימת כתובות האימייל לדף הפרטים של האימייל
כדי להתחיל, תוסיפו מעבר שיופיע כשלוחצים על אימייל. לשינוי הזה בניווט, דפוס הטרנספורמציה של הקונטיינר מתאים מאוד כי הוא מיועד למעברים בין רכיבי ממשק משתמש שמכילים קונטיינר. הדפוס הזה יוצר חיבור גלוי בין שני רכיבים בממשק המשתמש.
לפני שמוסיפים קוד, כדאי לנסות להפעיל את אפליקציית 'תשובה' וללחוץ על הודעת אימייל. היא אמורה לבצע דילוג פשוט, כך שהמסך יוחלף ללא מעבר:
מתחילים בהוספת מאפיין transitionName
ל-MaterialCardView
ב-email_item_layout.xml
, כפי שמוצג בקטע הקוד הבא:
email_item_layout.xml
android:transitionName="@{@string/email_card_transition_name(email.id)}"
שם המעבר מקבל במשאב מחרוזת עם פרמטר. עליך להשתמש במזהה של כל אימייל כדי לוודא שכל transitionName
בEmailFragment
שלנו הוא ייחודי.
עכשיו, אחרי שהגדרתם את שם המעבר של פריט רשימת האימייל, נבצע את אותו תהליך בפריסה של פרטי האימייל. ב-fragment_email.xml
, מגדירים את ה-transitionName
של MaterialCardView
למשאב המחרוזת הבא:
fragment_email.xml
android:transitionName="@string/email_card_detail_transition_name"
בקובץ HomeFragment.kt
, צריך להחליף את הקוד שבכתובת onEmailClicked
בקטע הקוד הבא כדי ליצור את המיפוי מתצוגת ההתחלה (פריט ברשימת האימיילים) ומתצוגת הסיום (מסך פרטי האימייל):
HomeFragment.kt
val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)
עכשיו, אחרי שהגדרתם את הצינורות, אתם יכולים ליצור טרנספורמציה של מאגר. בשיטה EmailFragment
onCreate
, מגדירים את sharedElementEnterTransition
למכונה חדשה של MaterialContainerTransform
(ייבוא הגרסה com.google.android.material.transition
לעומת הגרסה com.google.android.material.transition.platform
) על ידי הוספת קטע הקוד הבא:
EmailFragment.kt
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.nav_host_fragment
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}
עכשיו אפשר לנסות להפעיל מחדש את האפליקציה.
הכול מתחיל להיראות מצוין! כשלוחצים על הודעת אימייל ברשימת האימיילים, טרנספורמציה של מאגר צריכה להרחיב את פריט הרשימה לדף פרטים במסך מלא. עם זאת, שים לב איך לחיצה על 'חזרה' לא מכווצת את הודעת האימייל בחזרה לרשימה. בנוסף, רשימת כתובות האימייל תיעלם מיד בתחילת המעבר, ותציג את הרקע של החלון האפור. כך שעדיין לא סיימנו.
כדי לתקן את המעבר להחזרה, צריך להוסיף את שתי השורות הבאות ל-method onViewCreated
ב-HomeFragment.kt
:
HomeFragment.kt
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
כדאי לנסות להריץ מחדש את האפליקציה. לחיצה על 'הקודם' אחרי פתיחת הודעת אימייל תצמצם אותה בחזרה לרשימה. איזה יופי! נמשיך לשפר את האנימציה.
הבעיה של היעלמות רשימת האימיילים נובעת מכך שבמהלך הניווט אל קטע חדש באמצעות רכיב הניווט, הקטע הנוכחי מוסר מיד ומוחליף בקטע החדש שמגיע. כדי שרשימת כתובות האימייל תישאר גלויה גם אחרי ההחלפה, אפשר להוסיף מעבר ליציאה אל HomeFragment
.
צריך להוסיף את קטע הקוד הבא לשיטה HomeFragment
onEmailClicked
כדי שרשימת כתובות האימייל תקטן ביציאה ובחזרה אליה:
HomeFragment.kt
exitTransition = MaterialElevationScale(false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
בשלב הבא, כדי להבטיח שהמעבר של MaterialElevationScale
יחול במסך הבית כולו, במקום על כל אחת מהתצוגות הנפרדות בהיררכיה, צריך לסמן את RecyclerView
ב-fragment_home.xml
כקבוצת מעבר.
fragment_home.xml
android:transitionGroup="true"
בשלב הזה, עיבוד הנתונים בקונטיינר אמור לפעול בצורה תקינה. לחיצה על הודעת אימייל מרחיבה את הפריט לרשימה במסך פרטים, תוך ביטול רשימת כתובות האימייל. הקשה על מקש 'הקודם' מכווצת את מסך פרטי האימייל בחזרה לפריט ברשימה, תוך הגדלת קנה המידה ברשימת האימיילים.
5. הוספת טרנספורמציה של קונטיינר ממקש ה-FAB לדף כתיבת האימייל
נמשיך בטרנספורמציה של קונטיינר ונוסיף מעבר מלחצן הפעולה הצפה ל-ComposeFragment
, ונרחיב את לחצן ה-FAB לאימייל חדש שהמשתמש יכתוב. קודם כול, מפעילים מחדש את האפליקציה ולוחצים על לחצן ה-FAB כדי לראות שאין מעבר כשפותחים את המסך לכתיבה של אימייל.
אנחנו משתמשים באותה מחלקה, אבל הדרך שבה אנחנו מגדירים את המופע הזה תהיה שונה כי ה-FAB נמצא ב-MainActivity
וה-ComposeFragment
ממוקם בתוך המאגר של מארח הניווט MainActivity
.
ב-ComposeFragment.kt
, צריך להוסיף את קטע הקוד הבא לשיטה onViewCreated
, ולהקפיד לייבא את גרסת androidx.transition
של Slide
.
ComposeFragment.kt
enterTransition = MaterialContainerTransform().apply {
startView = requireActivity().findViewById(R.id.fab)
endView = emailCardView
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
scrimColor = Color.TRANSPARENT
containerColor = requireContext().themeColor(R.attr.colorSurface)
startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
addTarget(R.id.email_card_view)
}
בנוסף לפרמטרים ששימשו להגדרת הטרנספורמציה הקודמת של הקונטיינר, startView
ו-endView
מוגדרים כאן באופן ידני. במקום להשתמש במאפייני transitionName
כדי ליידע את מערכת המעבר של Android אילו תצוגות צריך לשנות, אפשר לציין אותן באופן ידני במקרה הצורך.
עכשיו יש להריץ מחדש את האפליקציה. ה-FAB אמור להשתנות למסך הכתיבה (יש לעיין בקובץ ה-GIF בסוף השלב הזה).
בדומה לשלב הקודם, צריך להוסיף מעבר ל-HomeFragment
כדי שהוא לא ייעלם אחרי שהוא יוסר ויוחלף ב-ComposeFragment
.
מעתיקים את קטע הקוד הבא ל-method navigateToCompose
ב-MainActivity
לפני הקריאה NavController
navigate
.
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialElevationScale(false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
זהו זה השלב הזה! אמור להיות מעבר מ-FAB למסך הכתיבה שנראה כך:
6. הוספת מעבר של ציר ה-Z המשותף מסמל החיפוש לדף תצוגת החיפוש
בשלב הזה, נוסיף מעבר מסמל החיפוש לתצוגת החיפוש במסך מלא. מכיוון שאין מאגר קבוע שמעורב בשינוי הניווט הזה, אנחנו יכולים להשתמש במעבר בציר Z משותף כדי לחזק את הקשר המרחבי בין שני המסכים ולציין מעבר לרמה אחת למעלה בהיררכיה של האפליקציה.
לפני שמוסיפים קוד נוסף, מנסים להפעיל את האפליקציה ולהקיש על סמל החיפוש בפינה השמאלית התחתונה של המסך. פעולה זו אמורה להציג את מסך תצוגת החיפוש ללא מעבר.
כדי להתחיל, צריך למצוא את ה-method navigateToSearch
ב-MainActivity
ולהוסיף את קטע הקוד הבא לפני הקריאה ל-method NavController
navigate
, כדי להגדיר יציאה מהמקטע הנוכחי ולהזין מחדש מעברים בציר ה-Z MaterialSharedAxis
.
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
בשלב הבא, מוסיפים את קטע הקוד הבא לשיטה onCreate
ב-SearchFragment
, שמגדיר את מעברי ה-MaterialSharedAxis
של הכניסה והחזרה.
SearchFragment.kt
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
לבסוף, כדי לוודא שהמעבר MaterialSharedAxis
יחול על מסך החיפוש כולו, במקום על כל אחד מהתצוגות הנפרדות בהיררכיה, מסמנים את LinearLayout
ב-fragment_search.xml
כקבוצת מעבר.
fragment_search.xml
android:transitionGroup="true"
זהו! עכשיו אפשר לנסות להפעיל מחדש את האפליקציה ולהקיש על סמל החיפוש. המסכים של תצוגת הבית ותצוגת החיפוש צריכים לדעוך ולהשתנות בו-זמנית לאורך ציר Z לעומק, כדי ליצור אפקט חלק בין שני המסכים.
7. הוספת מעבר עמעום בין דפי תיבות דואר
בשלב הזה נוסיף מעבר בין תיבות דואר שונות. אנחנו לא רוצים להדגיש קשר מרחבי או היררכי, לכן נשתמש בהעברה בהדרגה כדי לבצע 'החלפה' פשוטה בין רשימות של כתובות אימייל.
לפני שמוסיפים קוד נוסף, כדאי לנסות להפעיל את האפליקציה, להקיש על הלוגו של 'תשובה' בסרגל האפליקציות התחתון ולעבור בין תיבות דואר. רשימת כתובות האימייל אמורה להשתנות ללא מעבר.
כדי להתחיל, צריך לחפש את ה-method navigateToHome
ב-MainActivity
ולהוסיף את קטע הקוד הבא לפני הקריאה לשיטת NavController
מסוג navigate
, כדי להגדיר מעבר MaterialFadeThrough
מהמקטע הנוכחי.
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialFadeThrough().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
בשלב הבא, פותחים את HomeFragment
. ב-onCreate
, מגדירים את enterTransition
של החלקיק למכונה חדשה של MaterialFadeThrough
.
HomeFragment.kt
enterTransition = MaterialFadeThrough().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
להפעיל מחדש את האפליקציה. כשפותחים את חלונית ההזזה לניווט התחתונה ומחליפים תיבות דואר, רשימת האימיילים הנוכחית אמורה להתעמעם ולהקטין את התצוגה בזמן שהרשימה החדשה נעלמת. איזה יופי!
8. הוספת טרנספורמציה של קונטיינר מהצ'יפ של כתובת האימייל לתצוגת כרטיס
בשלב הזה, תוסיפו מעבר שממיר צ'יפ לכרטיס קופץ. כאן נעשה שימוש בטרנספורמציה של קונטיינר כדי ליידע את המשתמש שהפעולה שבוצעה בחלון הקופץ תשפיע על הצ'יפ שממנו הגיע החלון הקופץ.
לפני שמוסיפים קוד כלשהו, צריך להריץ את אפליקציית 'תשובה', ללחוץ על הודעת אימייל, ללחוץ על לחצן ה-FAB 'תשובה' ולנסות ללחוץ על הצ'יפ של הנמען ליצירת קשר. הצ'יפ אמור להיעלם באופן מיידי, וכרטיס עם כתובות האימייל של אותו איש קשר אמור להופיע בתצוגה בלי אנימציות.
בשלב הזה תעבדו ב-ComposeFragment
. הפריסה שכבר הוספת לפריסה ComposeFragment
היא צ'יפים של נמענים (גלויים כברירת מחדל) וכרטיס נמען (לא נראים כברירת מחדל). צ'יפ של נמען והכרטיס הזה הם שתי התצוגות שביניהן תיצרו טרנספורמציה של קונטיינר.
כדי להתחיל, פותחים את ComposeFragment
ומחפשים את השיטה expandChip
. המערכת קוראת לשיטה הזו כשמקישים על chip
שסופק. צריך להוסיף את קטע הקוד הבא מעל לשורות שמחליפה את הגדרת החשיפה recipientCardView
ו-chip
. הפעולה הזו תפעיל את הטרנספורמציה של מאגר התגים שרשום דרך beginDelayedTransition
.
ComposeFragment.kt
val transform = MaterialContainerTransform().apply {
startView = chip
endView = binding.recipientCardView
scrimColor = Color.TRANSPARENT
endElevation = requireContext().resources.getDimension(
R.dimen.email_recipient_card_popup_elevation_compat
)
addTarget(binding.recipientCardView)
}
TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)
אם תפעילו את האפליקציה עכשיו, הצ'יפ אמור להפוך לכרטיס עם כתובות האימייל של הנמען. בשלב הבא נגדיר את המעבר להחזרה כדי לכווץ את הכרטיס חזרה לצ'יפ.
בשיטה collapseChip
ב-ComposeFragment
, מוסיפים את קטע הקוד הבא כדי לכווץ את הכרטיס חזרה לצ'יפ.
ComposeFragment.kt
val transform = MaterialContainerTransform().apply {
startView = binding.recipientCardView
endView = chip
scrimColor = Color.TRANSPARENT
startElevation = requireContext().resources.getDimension(
R.dimen.email_recipient_card_popup_elevation_compat
)
addTarget(chip)
}
TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)
מפעילים מחדש את האפליקציה. לחיצה על הצ'יפ אמורה להרחיב את הצ'יפ לכרטיס, בזמן לחיצה על הכרטיס, לכווץ את הכרטיס בחזרה לצ'יפ. איזה יופי!
9. הפעולה הושלמה
בעזרת פחות מ-100 שורות קוד ב-Kotlin ותגי XML בסיסיים, ספריית MDC-Android עזרה לכם ליצור מעברים יפים באפליקציה קיימת שתואמת להנחיות של Material Design, וגם נראית ומתנהגת באופן עקבי בכל מכשירי Android.
השלבים הבאים
מידע נוסף על מערכת התנועה של Material זמין במפרט ובמסמכי העזרה המלאים למפתחים. מומלץ גם לנסות להוסיף כמה מעברים של Material לאפליקציה.
תודה שניסית תנועה בעיצוב חדשני. אנחנו מקווים שנהנית מה-Codelab הזה.