إنشاء تأثيرات انتقالية جميلة باستخدام ميزة Material Motion لنظام Android

1. مقدمة

‫التصميم المتعدد الأبعاد هو نظام لإنشاء منتجات رقمية جريئة وجميلة. من خلال توحيد الأسلوب والعلامة التجارية والتفاعل والحركة ضمن مجموعة متسقة من المبادئ والمكوّنات، يمكن لفِرق المنتجات تحقيق أكبر إمكانات التصميم.

logo_components_color_2x_web_96dp.png

تساعد Material Components (MDC) المطوّرين في تنفيذ التصميم المتعدد الأبعاد. تم إنشاء MDC بواسطة فريق من المهندسين ومصممي تجربة المستخدم في Google، وتتضمّن عشرات المكوّنات الجميلة والوظيفية لواجهة المستخدم، وهي متاحة على Android وiOS والويب وFlutter.material.io/develop

ما هو نظام الحركة في Material لنظام التشغيل Android؟

نظام الحركة في Material لنظام التشغيل Android هو مجموعة من أنماط الانتقال ضِمن مكتبة MDC-Android التي يمكن أن تساعد المستخدمين في فهم التطبيق والتنقّل فيه، كما هو موضّح في إرشادات Material Design.

في ما يلي أنماط الانتقال الأربعة الرئيسية في Material:

  • تحويل الحاوية: تأثيرات الانتقال بين العناصر في واجهة المستخدم التي تتضمّن حاوية، وينشئ تأثير ربط مرئي بين عنصرين مختلفين في واجهة المستخدم من خلال تحويل أحد العناصر إلى عنصر آخر بسلاسة.
  • المحور المشترك: تأثيرات الانتقال بين العناصر في واجهة المستخدم التي تربطها علاقة انتقال أو علاقة مكانية، ويستخدم تحويلاً مشتركًا على محور "س" أو "ص" أو "ع" لتعزيز العلاقة بين العناصر.
  • التلاشي التدريجي: يتم استخدامه للانتقال بين عناصر واجهة المستخدم التي لا تربطها علاقة قوية ببعضها، ويستخدم التلاشي التدريجي المتسلسل والتلاشي التدريجي للظهور، مع مقياس للعنصر الوارد.
  • التلاشي: يُستخدم مع عناصر واجهة المستخدم التي تدخل في حدود الشاشة أو تخرج منها.

توفّر مكتبة MDC-Android فئات انتقالية لهذه الأنماط، وهي تستند إلى كلّ من مكتبة AndroidX Transition (androidx.transition) وإطار عمل Android Transition (android.transition):

AndroidX

  • مضمّن في حزمة com.google.android.material.transition
  • متوافق مع المستوى 14 من واجهة برمجة التطبيقات والإصدارات الأحدث
  • يتوافق مع "اللقطات" و"طرق العرض"، ولكن ليس مع "الأنشطة" أو "النوافذ"
  • يتضمّن إصلاحات أخطاء متوافقة مع الإصدارات القديمة وسلوكًا متسقًا في جميع مستويات واجهة برمجة التطبيقات

إطار عمل

  • مضمّن في حزمة com.google.android.material.transition.platform
  • متوافق مع المستوى 21 من واجهة برمجة التطبيقات والإصدارات الأحدث
  • يتوافق مع "اللقطات" و"طرق العرض" و"الأنشطة" و"النوافذ"
  • إصلاحات الأخطاء التي لم يتم نقلها إلى الإصدارات القديمة وقد يختلف سلوكها باختلاف مستويات واجهة برمجة التطبيقات

في هذا الدرس التطبيقي حول الترميز، ستستخدم عمليات الانتقال المستندة إلى Material والمبنية على مكتبة AndroidX، ما يعني أنّك ستركز بشكل أساسي على "اللقطات" و"طرق العرض".

ما ستنشئه

سيرشدك هذا الدرس التطبيقي حول الترميز إلى خطوات إنشاء بعض عمليات الانتقال في تطبيق بريد إلكتروني تجريبي على Android يُسمى ردّ باستخدام Kotlin، وذلك لتوضيح كيفية استخدام عمليات الانتقال من مكتبة MDC-Android لتخصيص مظهر تطبيقك وإحساسه.

سيتم توفير الرمز الأولي لتطبيق Reply، وستدمج انتقالات Material التالية في التطبيق، والتي يمكن رؤيتها في صورة GIF الخاصة بدرس البرمجة المكتمل أدناه:

  • انتقال تحويل الحاوية من قائمة عناوين البريد الإلكتروني إلى صفحة تفاصيل الرسالة الإلكترونية
  • انتقال Container Transform من زر الإجراء الرئيسي (FAB) إلى صفحة إنشاء رسالة إلكترونية
  • الانتقال باستخدام محور "ع" المشترك من رمز البحث إلى صفحة عرض البحث
  • الانتقال بين صفحات صندوق البريد باستخدام تأثير التلاشي
  • الانتقال باستخدام Container Transform من شريحة عنوان البريد الإلكتروني إلى "عرض البطاقة"

لم تتم إضافة نطاق الإطار المتضمّن المطلوب (youtu.be) إلى القائمة البيضاء.

المتطلبات

  • معرفة أساسية بتطوير تطبيقات Android ولغة Kotlin
  • استوديو Android (يمكنك تنزيله من هنا إذا لم يكن مثبّتًا لديك)
  • محاكي Android أو جهاز Android (متاح من خلال استوديو Android)
  • الرمز النموذجي (راجِع الخطوة التالية)

ما هو تقييمك لمستوى خبرتك في إنشاء تطبيقات Android؟

مبتدئ متوسط متقدّم

2. إعداد بيئة التطوير

بدء تشغيل "استوديو Android"

عند فتح استوديو Android، من المفترض أن تظهر نافذة بعنوان "مرحبًا بك في استوديو Android". ومع ذلك، إذا كانت هذه هي المرة الأولى التي تشغّل فيها "استوديو Android"، عليك اتّباع خطوات معالج إعداد "استوديو Android" باستخدام القيم التلقائية. قد تستغرق هذه الخطوة عدة دقائق لتنزيل الملفات اللازمة وتثبيتها، لذا يمكنك تركها تعمل في الخلفية أثناء تنفيذ القسم التالي.

الخيار 1: استنساخ تطبيق الدرس التطبيقي حول الترميز التمهيدي من GitHub

لاستنساخ هذا الدرس التطبيقي حول الترميز من GitHub، شغِّل الأوامر التالية:

git clone https://github.com/material-components/material-components-android-motion-codelab.git
cd material-components-android-motion-codelab

الخيار 2: تنزيل ملف zip لتطبيق الدرس التطبيقي حول الترميز للمبتدئين

يقع التطبيق الأولي في الدليل material-components-android-motion-codelab-develop.

تحميل رمز البداية في "استوديو Android"

  1. بعد انتهاء معالج الإعداد وظهور النافذة مرحبًا بك في "استوديو Android"، انقر على فتح مشروع حالي في "استوديو Android".

e3f200327a67a53.png

  1. انتقِل إلى الدليل الذي ثبّت فيه نموذج الرمز البرمجي واختَر دليل النموذج لفتح المشروع.
  2. انتظِر لحظة إلى أن ينتهي "استوديو Android" من إنشاء المشروع ومزامنته، كما هو موضّح من خلال مؤشرات النشاط في أسفل نافذة "استوديو Android".
  1. في هذه المرحلة، قد يعرض "استوديو Android" بعض أخطاء الإنشاء لأنّك لم تثبِّت حزمة تطوير البرامج (SDK) لنظام التشغيل Android أو أدوات الإنشاء، مثل الخطأ الموضّح أدناه. اتّبِع التعليمات الواردة في "استوديو Android" لتثبيت/تعديل هذه الحزم ومزامنة مشروعك. إذا كنت لا تزال تواجه مشاكل، اتّبِع الدليل حول تحديث أدواتك باستخدام SDK Manager.

6e026ae171f5b1eb.png

التحقّق من تبعيات المشروع

يحتاج المشروع إلى الاعتماد على مكتبة MDC-Android. من المفترض أن يتضمّن رمزك النموذجي الذي نزّلته هذه الاعتمادية، ولكن لنلقِ نظرة على الإعدادات للتأكّد من ذلك.

انتقِل إلى ملف build.gradle الخاص بالوحدة app وتأكَّد من أنّ وحدة التصميم dependencies تتضمّن اعتمادية على MDC-Android:

implementation 'com.google.android.material:material:1.2.0'

تشغيل تطبيق المبتدئين

  1. تأكَّد من أنّ إعدادات التصميم على يمين خيار الجهاز هي app.
  2. اضغط على زر التشغيل / التنفيذ الأخضر لإنشاء التطبيق وتشغيله.

24218d0a6ae25803.png

  1. في نافذة اختيار هدف النشر، إذا كان لديك جهاز Android مُدرَج في الأجهزة المتاحة، انتقِل إلى الخطوة 8. بخلاف ذلك، انقر على إنشاء جهاز افتراضي جديد.
  2. في شاشة اختيار الجهاز، اختَر جهاز هاتف، مثل Pixel 3، ثم انقر على التالي.
  3. في شاشة صورة النظام، اختَر إصدارًا حديثًا من Android، ويُفضّل اختيار أعلى مستوى لواجهة برمجة التطبيقات. إذا لم يكن مثبّتًا، انقر على الرابط تنزيل الذي يظهر وأكمِل عملية التنزيل.
  4. انقر على التالي.
  5. في شاشة الجهاز الافتراضي المتوافق مع Android (AVD)، اترك الإعدادات كما هي وانقر على إنهاء.
  6. اختَر جهاز Android من مربّع حوار "هدف النشر".
  7. انقر على حسنًا.
  8. ينشئ استوديو Android التطبيق وينشره ويفتحه تلقائيًا على جهاز الاختبار.

اكتمال النقل بنجاح يجب أن يكون الرمز الأوّلي للصفحة الرئيسية لتطبيق Reply قيد التشغيل في المحاكي. من المفترض أن يظهر لك البريد الوارد الذي يحتوي على قائمة بالرسائل الإلكترونية.

cc73eb0d0f779035.png

اختياري: إبطاء الصور المتحركة على الجهاز

بما أنّ هذا الدرس التطبيقي حول الترميز يتضمّن انتقالات سريعة ولكنها سلسة، قد يكون من المفيد إبطاء الصور المتحركة على الأجهزة لملاحظة بعض التفاصيل الدقيقة للانتقالات أثناء تنفيذها. يمكن إجراء ذلك باستخدام أوامر adb shell أو مربّع "الإعدادات السريعة". يُرجى العِلم أنّ هذه الطرق لإبطاء الرسوم المتحركة على الجهاز ستؤثر أيضًا في الرسوم المتحركة خارج تطبيق "ردّ".

الطريقة 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: مربّع الإعدادات السريعة

بدلاً من ذلك، لإعداد مربّع "الإعدادات السريعة"، عليك أولاً تفعيل "إعدادات المطوّرين" على جهازك إذا لم يسبق لك إجراء ذلك:

  1. افتح تطبيق "الإعدادات" على الجهاز
  2. انتقِل إلى أسفل الصفحة وانقر على "لمحة عن الجهاز المحاكي".
  3. انتقِل للأسفل وانقر بسرعة على "رقم الإصدار" إلى أن يتم تفعيل "إعدادات المطوّرين".

بعد ذلك، اتّبِع الخطوات التالية، مع البقاء في تطبيق "الإعدادات" على الجهاز، لتفعيل مربّع "الإعدادات السريعة":

  1. انقر على رمز البحث أو شريط البحث في أعلى الشاشة
  2. اكتب "المربّعات" في حقل البحث
  3. انقر على صف "فئات مطوّري البرامج في الإعدادات السريعة".
  4. انقر على مفتاح التبديل "سرعة الصور المتحركة للنافذة"

أخيرًا، خلال الدرس التطبيقي حول الترميز، اسحب مركز إشعارات النظام للأسفل من أعلى الشاشة واستخدِم الرمز c7e3f98200023f6a.png للتبديل بين سرعة الرسوم المتحركة البطيئة والعادية.

3- التعرّف على رمز نموذج التطبيق

لنلقِ نظرة على التعليمات البرمجية. قدّمنا تطبيقًا يستخدم مكتبة مكوّن Jetpack Navigation للتنقّل بين بعض الفئات Fragment المختلفة، وكل ذلك ضمن نشاط واحد، وهو MainActivity:

  • HomeFragment: تعرض قائمة بالرسائل الإلكترونية
  • EmailFragment: تعرض رسالة إلكترونية واحدة وكاملة
  • تتيح ComposeFragment: إنشاء رسالة إلكترونية جديدة
  • SearchFragment: يعرض طريقة عرض البحث

أولاً، لفهم كيفية إعداد الرسم البياني للتنقّل في التطبيق، افتح 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)
}

يوضّح هذا الرمز البرمجي كيف يمكنك الانتقال إلى صفحة عرض البحث بدون أي انتقال مخصّص. خلال هذا الدرس التطبيقي حول الترميز، ستتعمّق في MainActivity في تطبيق "الرد الذكي" وأربع أجزاء رئيسية لإعداد عمليات انتقال التصميم المتعدد الأبعاد التي تعمل بالتزامن مع إجراءات التنقّل المختلفة في جميع أنحاء التطبيق.

بعد أن تعرّفت على الرمز الأولي، لننفّذ الآن أول انتقال.

4. إضافة انتقال Container Transform من قائمة عناوين البريد الإلكتروني إلى صفحة تفاصيل الرسالة الإلكترونية

للبدء، عليك إضافة انتقال عند النقر على رسالة إلكترونية. بالنسبة إلى تغيير التنقّل هذا، يكون نمط تحويل الحاوية مناسبًا تمامًا، لأنّه مصمّم لتأثيرات الانتقال بين العناصر في واجهة المستخدم التي تتضمّن حاوية. ينشئ هذا النمط تأثير ربط مرئي بين عنصرين في واجهة المستخدم.

قبل إضافة أي رمز، جرِّب تشغيل تطبيق Reply والنقر على رسالة إلكترونية. يجب أن يتم إجراء قطع سريع بسيط، ما يعني استبدال الشاشة بدون انتقال:

f0e8a92eb2216bce.gif

ابدأ بإضافة السمة 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))
}

الآن، حاوِل إعادة تشغيل التطبيق.

ed62cedec31da268.gif

بدأت الأمور تبدو رائعة. عند النقر على رسالة إلكترونية في قائمة الرسائل الإلكترونية، يجب أن يؤدي انتقال الحاوية إلى توسيع عنصر القائمة ليصبح صفحة تفاصيل بملء الشاشة. ومع ذلك، لاحظ كيف أنّ الضغط على زر الرجوع لا يؤدي إلى تصغير الرسالة الإلكترونية وإعادتها إلى القائمة. بالإضافة إلى ذلك، تختفي قائمة عناوين البريد الإلكتروني فورًا في بداية عملية الانتقال، ويظهر خلفية النافذة الرمادية. لذلك لم ننتهِ بعد.

لإصلاح عملية الانتقال إلى الصفحة السابقة، أضِف السطرَين التاليَين إلى طريقة onViewCreated في HomeFragment.kt:

HomeFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

جرِّب إعادة تشغيل التطبيق. سيؤدي الضغط على زر الرجوع بعد فتح رسالة إلكترونية إلى تصغير الرسالة الإلكترونية وإعادتها إلى القائمة. أحسنت. لنواصل تحسين الصورة المتحركة.

تحدث مشكلة اختفاء قائمة عناوين البريد الإلكتروني لأنّه عند الانتقال إلى Fragment جديد باستخدام Navigation Component، تتم إزالة Fragment الحالي على الفور واستبداله بـ Fragment الجديد الوارد. لإبقاء قائمة عناوين البريد الإلكتروني مرئية حتى بعد استبدالها، يمكنك إضافة انتقال خروج إلى 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"

في هذه المرحلة، يجب أن يكون لديك عملية تحويل حاوية تعمل بشكل كامل. يؤدي النقر على رسالة إلكترونية إلى توسيع عنصر القائمة ليصبح شاشة تفاصيل مع إخفاء قائمة الرسائل الإلكترونية. يؤدي الضغط على زر الرجوع إلى تصغير شاشة تفاصيل الرسالة الإلكترونية وإرجاعها إلى عنصر قائمة مع تكبيرها في قائمة الرسائل الإلكترونية.

9df2b39d5a150418.gif

5- إضافة انتقال "تحويل الحاوية" من زر الإجراء العائم إلى صفحة إنشاء رسالة إلكترونية

لنواصل استخدام ميزة "تحويل الحاوية" ونضيف انتقالاً من "زر الإجراء العائم" إلى ComposeFragment، مع توسيع "زر الإجراء العائم" إلى رسالة إلكترونية جديدة يكتبها المستخدم. أعِد تشغيل التطبيق أولاً وانقر على زر الإجراء الرئيسي (FAB) لترى أنّه لا يوجد انتقال عند تشغيل شاشة إنشاء الرسالة الإلكترونية.

d242c9708abd382c.gif

على الرغم من أنّنا نستخدم فئة الانتقال نفسها، ستختلف طريقة ضبط هذه النسخة لأنّ زر الإجراء الرئيسي (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 Transition بالعناصر التي يجب تحويلها، يمكنك تحديد هذه العناصر يدويًا عند الضرورة.

الآن، أعِد تشغيل التطبيق. من المفترض أن يظهر لك الزر العائم للعمل السريع وهو يتحوّل إلى شاشة الإنشاء (راجِع صورة GIF في نهاية هذه الخطوة).

على غرار الخطوة السابقة، عليك إضافة انتقال إلى HomeFragment لمنع اختفائه بعد إزالته واستبداله بـ ComposeFragment.

انسخ المقتطف أدناه والصِقه في طريقة 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()
   }
}

هذا كل ما في هذه الخطوة. يجب أن يكون لديك انتقال من زر الإجراء العائم إلى شاشة الإنشاء بالشكل التالي:

81b68391ac4b0a9.gif

6. إضافة انتقال "محور ع المشترك" من رمز البحث إلى صفحة عرض البحث

في هذه الخطوة، سنضيف انتقالًا من رمز البحث إلى عرض البحث بملء الشاشة. بما أنّه لا يوجد حاوية ثابتة متضمّنة في تغيير التنقّل هذا، يمكننا استخدام انتقال "محور Z المشترك" لتعزيز العلاقة المكانية بين الشاشتين والإشارة إلى الانتقال بمستوى واحد للأعلى في التسلسل الهرمي للتطبيق.

قبل إضافة أي رمز إضافي، جرِّب تشغيل التطبيق والنقر على رمز البحث في أسفل يسار الشاشة. من المفترض أن يؤدي ذلك إلى ظهور شاشة عرض البحث بدون انتقال.

499e1a677b4216bb.gif

للبدء، ابحث عن طريقة navigateToSearch في MainActivity، وأضِف مقتطف الرمز التالي قبل طلب إجراء NavController navigate لإعداد عمليات الانتقال الحالية بين الخروج وإعادة الدخول في الجزء MaterialSharedAxis على المحور Z.

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 في العمق، ما يؤدي إلى إنشاء تأثير سلس بين الشاشتين.

e5c0b0a130e807db.gif

7. إضافة تأثير "التلاشي" للانتقال بين صفحات صندوق البريد

في هذه الخطوة، سنضيف انتقالًا بين صناديق البريد المختلفة. بما أنّنا لا نريد التأكيد على علاقة مكانية أو هرمية، سنستخدم تأثير التلاشي لإجراء عملية "تبديل" بسيطة بين قوائم الرسائل الإلكترونية.

قبل إضافة أي رمز إضافي، جرِّب تشغيل التطبيق والنقر على شعار "الردّ" في شريط التطبيق السفلي وتبديل صناديق البريد. يجب أن تتغيّر قائمة الرسائل الإلكترونية بدون أي انتقال.

2c874c0a4588e8fb.gif

للبدء، ابحث عن طريقة 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()
}

أعِد تشغيل التطبيق. عند فتح لوحة التنقّل السفلية وتغيير صناديق البريد، من المفترض أن تتلاشى قائمة الرسائل الإلكترونية الحالية وتتوسّع، بينما تتلاشى القائمة الجديدة وتتوسّع. أحسنت.

f61dfd58ea7bd3fd.gif

8. إضافة انتقال Container Transform من شريحة عنوان البريد الإلكتروني إلى عرض البطاقة

في هذه الخطوة، ستضيف انتقالاً يحوّل شريحة إلى بطاقة منبثقة. يتم استخدام عملية تحويل الحاوية هنا للمساعدة في إعلام المستخدم بأنّ الإجراء المتّخذ في النافذة المنبثقة سيؤثر في الشريحة التي نشأت منها النافذة المنبثقة.

قبل إضافة أي رمز، شغِّل تطبيق Reply، وانقر على رسالة إلكترونية، ثم على زر الإجراء العائم "رد"، وحاوِل النقر على شريحة جهة اتصال أحد المستلمين. يجب أن تختفي الشريحة على الفور وأن تظهر بطاقة تتضمّن عناوين البريد الإلكتروني لجهة الاتصال هذه بدون أي رسوم متحركة.

6200c682da2382d5.gif

ستعمل في 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)

أعِد تشغيل التطبيق. من المفترض أن يؤدي النقر على الشريحة إلى توسيعها لتصبح بطاقة، بينما يؤدي النقر على البطاقة إلى تصغيرها لتصبح شريحة مرة أخرى. أحسنت.

e823b28e2890e05d.gif

9- تم

باستخدام أقل من 100 سطر من رمز Kotlin وبعض ترميز XML الأساسي، ساعدتك مكتبة MDC-Android في إنشاء انتقالات رائعة في تطبيق حالي يتوافق مع إرشادات التصميم المتعدد الأبعاد، كما أنّها تبدو وتعمل بشكل متسق على جميع أجهزة Android.

454a47ba96017a25.gif

الخطوات التالية

للحصول على مزيد من المعلومات حول نظام Material motion، احرص على الاطّلاع على المواصفات ومستندات المطوّرين الكاملة، وجرِّب إضافة بعض انتقالات Material إلى تطبيقك.

نشكرك على تجربة Material motion. نأمل أن يكون هذا الدرس التطبيقي حول الترميز قد نال إعجابك.

تمكّنتُ من إكمال هذا الدرس التطبيقي حول الترميز خلال فترة زمنية معقولة وبجهد معقول

أوافق بشدة أوافق لا أوافق ولا أعارض لا أوافق لا أوافق أبدًا

أريد مواصلة استخدام نظام Material motion في المستقبل

أوافق بشدة أوافق لا أوافق ولا أعارض لا أوافق لا أوافق أبدًا