تحريك تغييرات التنسيق باستخدام عملية نقل

تجربة طريقة Compose
‫Jetpack Compose هي مجموعة أدوات واجهة المستخدِم المقترَحة لنظام Android. تعرَّفوا على كيفية استخدام الصور المتحركة في Compose.

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

يتضمّن إطار عمل الانتقال الميزات التالية:

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

للاطّلاع على رمز نموذجي يضيف حركة بين تغييرات التنسيق، يُرجى مراجعة BasicTransition.

في ما يلي العملية الأساسية لإضافة حركة بين تنسيقَين:

  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). إنّ استدعاء هذه الدالة الإنشائية يعادل استدعاء الدالة 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);

إنشاء إجراءات المشهد

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

تكون إجراءات المشهد مفيدة في الحالات التالية:

  • لإضافة حركة إلى طرق العرض التي ليست في التدرّج الهرمي نفسه: يمكنكم إضافة حركة إلى طرق العرض لمشهدَي البدء والانتهاء باستخدام إجراءات مشهدَي الخروج والدخول. يمكنك إضافة حركة إلى المشاهد التي تبدأ وتنتهي باستخدام إجراءات المشهد عند الخروج والدخول.
  • لإضافة حركة إلى طرق العرض التي لا يمكن لإطار عمل الانتقالات إضافة حركة إليها تلقائيًا، مثل 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);

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

إذا لم تحدّدوا مثيل انتقال، يمكن لمدير الانتقال تطبيق انتقال تلقائي يقدّم إجراءً مناسبًا لمعظم الحالات. لمزيد من المعلومات، يُرجى الاطّلاع على مرجع واجهة برمجة التطبيقات للفئة TransitionManager.

اختيار طرق عرض مستهدَفة محدّدة

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

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

لإزالة طريقة عرض واحدة أو أكثر من قائمة الأهداف، استدعوا الـ removeTarget() قبل بدء الانتقال. لإضافة طرق العرض التي تحدّدونها فقط إلى الـ قائمة الأهداف، استدعوا الـ addTarget() دالة. لمزيد من المعلومات، يُرجى الاطّلاع على مرجع واجهة برمجة التطبيقات للفئة 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.

تحديد وظائف ردّ الاتصال لدورة حياة الانتقال

تشبه دورة حياة الانتقال مراحل النشاط. تمثّل حالات الانتقال التي يراقبها إطار العمل خلال الفترة بين استدعاء الدالة TransitionManager.go() واكتمال الصورة المتحركة. في حالات دورة الحياة المهمة، يستدعي إطار العمل وظائف ردّ الاتصال المحدّدة بواسطة واجهة TransitionListener.

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

لمزيد من المعلومات، يُرجى الاطّلاع على مرجع واجهة برمجة التطبيقات للفئة TransitionListener.

القيود

يسرد هذا القسم بعض القيود المعروفة في إطار عمل الانتقالات:

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