توفّر واجهة برمجة التطبيقات Fragment API طريقتَين لاستخدام تأثيرات الحركة والإحالات الناجحة.
لربط الأجزاء مرئيًا أثناء التنقل. وأحد هذه الأساليب هو
وإطار عمل الصور المتحركة، والذي يستخدم كلاً من
Animation
و
Animator
تشير رسالة الأشكال البيانية
الآخر هو إطار النقل، الذي يتضمن
انتقالات العناصر المشتركة.
يمكنك تحديد تأثيرات مخصصة لإدخال الأجزاء والخروج منها، انتقالات العناصر المشتركة بين الأجزاء.
- يحدِّد تأثير Enter كيفية دخول الجزء إلى الشاشة. على سبيل المثال: يمكنك إنشاء تأثير لتمرير الجزء من حافة الشاشة عند الانتقال إليها.
- يحدد تأثير الخروج كيفية خروج الجزء من الشاشة. على سبيل المثال: يمكنك إنشاء تأثير لإخفاء الجزء عند الانتقال بعيدًا منه.
- يحدد انتقال العنصر المشترك كيفية مشاركة طريقة العرض بين
يتحرك جزآن بينهما. على سبيل المثال، الصورة المعروضة
في
ImageView
في الكسر A ينتقل إلى الكسر B مرة واحدة B مرئية.
ضبط الصور المتحركة
أولاً، تحتاج إلى إنشاء رسوم متحركة لتأثيرات الدخول والخروج، وهي تشغيلها عند الانتقال إلى جزء جديد. يمكنك تحديد الرسوم المتحركة موارد الصور المتحركة في مرحلة ما قبل المدرسة. وتتيح لك هذه الموارد تحديد كيفية تدوير الأجزاء وتمديدها وتلاشيها والتحرك أثناء الرسوم المتحركة. على سبيل المثال، قد تريد الجزء الحالي ليتلاشى وينزل الجزء الجديد من الحافة اليمنى للشاشة، كما هو موضح في الشكل 1.
![إدخال الصور المتحركة والخروج منها يتلاشى الجزء الحالي أثناء
ينزلق الجزء التالي من اليمين.](https://developer.android.google.cn/static/images/training/basics/fragments/enter-exit-animation.gif?authuser=0000&hl=ar)
يمكن تحديد هذه الصور المتحركة في دليل res/anim
:
<!-- res/anim/fade_out.xml -->
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="1"
android:toAlpha="0" />
<!-- res/anim/slide_in.xml -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="100%"
android:toXDelta="0%" />
ويمكنك أيضًا تحديد الرسوم المتحركة لتأثيرات الدخول والخروج التي يتم تشغيلها.
عند فرقعة المكدس الخلفي، وهو ما قد يحدث عندما ينقر المستخدم فوق المكدس لأعلى أو
زر الرجوع وتُعرف هذه الحركة باسم الحركة popEnter
وpopExit
. بالنسبة
على سبيل المثال، عندما يعود مستخدم إلى شاشة سابقة، قد ترغب في
الجزء الحالي للخروج من الحافة اليمنى للشاشة والجزء السابق
حتى تتلاشى.
![الرسوم المتحركة لـpopEnter والنافذة المنبثقة للخروج. يتم إيقاف الجزء الحالي
الشاشة إلى اليمين بينما يتلاشى الجزء السابق.](https://developer.android.google.cn/static/images/training/basics/fragments/pop-animations.gif?authuser=0000&hl=ar)
popEnter
و
popExit
صورة متحركة ينزلق الجزء الحالي خارج الشاشة
إلى اليسار بينما يتلاشى الجزء السابق.يمكن تعريف هذه الرسوم المتحركة على النحو التالي:
<!-- res/anim/slide_out.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="0%"
android:toXDelta="100%" />
<!-- res/anim/fade_in.xml -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0"
android:toAlpha="1" />
وبمجرد تحديد الصور المتحركة، يمكنك استخدامها عن طريق استدعاء
FragmentTransaction.setCustomAnimations()
،
تمرير موارد الصور المتحركة من خلال رقم تعريف المورد، كما هو موضح في
المثال التالي:
Kotlin
supportFragmentManager.commit { setCustomAnimations( R.anim.slide_in, // enter R.anim.fade_out, // exit R.anim.fade_in, // popEnter R.anim.slide_out // popExit ) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setCustomAnimations( R.anim.slide_in, // enter R.anim.fade_out, // exit R.anim.fade_in, // popEnter R.anim.slide_out // popExit ) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
ضبط الانتقالات
ويمكنك أيضًا استخدام الانتقالات لتحديد تأثيرات الدخول والخروج. هذه يمكن تحديد الانتقالات في ملفات موارد XML. على سبيل المثال، قد تريد أن يتلاشى الجزء الحالي ويختفي الجزء الجديد من الحافة اليمنى من الشاشة. يمكن تحديد هذه الانتقالات على النحو التالي:
<!-- res/transition/fade.xml -->
<fade xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"/>
<!-- res/transition/slide_right.xml -->
<slide xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:slideEdge="right" />
بعد تحديد الانتقالات، يمكنك تطبيقها عن طريق طلب
setEnterTransition()
على جزء الإدخال
setExitTransition()
على الجزء النهائي، وتمرير موارد النقل المتضخمة
حسب معرّف المورد، كما هو موضّح في المثال التالي:
Kotlin
class FragmentA : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val inflater = TransitionInflater.from(requireContext()) exitTransition = inflater.inflateTransition(R.transition.fade) } } class FragmentB : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(R.transition.slide_right) } }
Java
public class FragmentA extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TransitionInflater inflater = TransitionInflater.from(requireContext()); setExitTransition(inflater.inflateTransition(R.transition.fade)); } } public class FragmentB extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TransitionInflater inflater = TransitionInflater.from(requireContext()); setEnterTransition(inflater.inflateTransition(R.transition.slide_right)); } }
دعم الأجزاء عمليات انتقال AndroidX: وفي حين أنّ الأجزاء تتوافق أيضًا التحولات في إطار العمل، فإننا نشدد على ننصحك باستخدام عمليات انتقال AndroidX، لأنّها متاحة في المستوى 14 من واجهة برمجة التطبيقات والإصدار الأعلى والتي تحتوي على إصلاحات أخطاء غير موجودة في الإصدارات القديمة من وانتقالات أطر العمل.
استخدام انتقالات العناصر المشتركة
جزء من إطار النقل،
تحدد انتقالات العناصر المشتركة كيفية تنقل طرق العرض المقابلة بين
جزأين أثناء انتقال الجزء. على سبيل المثال، قد تريد
صورة معروضة في ImageView
على الجزء "أ" للانتقال إلى الجزء "ب"
بمجرد أن تصبح B مرئية، كما هو موضح في الشكل 3.
![انتقال جزء مع عنصر مشترك.](https://developer.android.google.cn/static/images/training/basics/fragments/shared-element-transition.gif?authuser=0000&hl=ar)
إليك كيفية إجراء انتقال للأجزاء باستخدام العناصر المشتركة، وذلك على مستوى عالٍ:
- عيِّن اسم انتقال فريدًا لكل عرض عنصر مشترك.
- أضف طرق عرض العناصر المشتركة وأسماء النقلات إلى
FragmentTransaction
- ضبط رسم متحرك لعنصر مشترك
أولاً، يجب تعيين اسم انتقال فريد لكل عرض عنصر مشترك
للسماح بربط طرق العرض من جزء إلى آخر. إعداد
اسم الانتقال على العناصر المشتركة في كل تخطيط جزء باستخدام
ViewCompat.setTransitionName()
،
يوفّر التوافق مع مستويات واجهة برمجة التطبيقات 14 والمستويات الأعلى.
على سبيل المثال، اسم النقل لـ ImageView
في الجزأين A وB
على النحو التالي:
Kotlin
class FragmentA : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... val itemImageView = view.findViewById<ImageView>(R.id.item_image) ViewCompat.setTransitionName(itemImageView, “item_image”) } } class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... val heroImageView = view.findViewById<ImageView>(R.id.hero_image) ViewCompat.setTransitionName(heroImageView, “hero_image”) } }
Java
public class FragmentA extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... ImageView itemImageView = view.findViewById(R.id.item_image); ViewCompat.setTransitionName(itemImageView, “item_image”); } } public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... ImageView heroImageView = view.findViewById(R.id.hero_image); ViewCompat.setTransitionName(heroImageView, “hero_image”); } }
لتضمين العناصر المشتركة في نقل الأجزاء، يجب
يجب أن يعرف FragmentTransaction
كيفية تحديد طريقة عرض كل عنصر مشترك من عنصر
إلى الجزء التالي. أضف كل عنصر من العناصر المشتركة إلى
FragmentTransaction
عن طريق الاتصال
FragmentTransaction.addSharedElement()
,
المرور في العرض واسم الانتقال للعرض المقابل في
الجزء التالي، كما هو موضح في المثال التالي:
Kotlin
val fragment = FragmentB() supportFragmentManager.commit { setCustomAnimations(...) addSharedElement(itemImageView, “hero_image”) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setCustomAnimations(...) .addSharedElement(itemImageView, “hero_image”) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
لتحديد كيفية انتقال العناصر المشتركة من جزء إلى آخر،
يجب تعيين انتقال enter على الجزء الذي
الانتقال إليها. اتصل
Fragment.setSharedElementEnterTransition()
في طريقة onCreate()
للجزء، كما هو موضَّح في المثال التالي:
Kotlin
class FragmentB : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedElementEnterTransition = TransitionInflater.from(requireContext()) .inflateTransition(R.transition.shared_image) } }
Java
public class FragmentB extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Transition transition = TransitionInflater.from(requireContext()) .inflateTransition(R.transition.shared_image); setSharedElementEnterTransition(transition); } }
يتم تحديد انتقال shared_image
على النحو التالي:
<!-- res/transition/shared_image.xml -->
<transitionSet>
<changeImageTransform />
</transitionSet>
يمكن استخدام جميع الفئات الفرعية من Transition
كعمليات انتقال عناصر مشتركة. في حال حذف
أردت إنشاء Transition
مخصّصة، اطّلِع على
إنشاء رسم متحرك مخصص:
changeImageTransform
، المستخدَم في المثال السابق، هو أحد الخيارات المتاحة
الترجمات سابقة الإعداد التي يمكنك استخدامها. يمكنك العثور على Transition
إضافية.
الفئات الفرعية في مرجع واجهة برمجة التطبيقات
صف واحد (Transition
).
بشكل افتراضي، يتم أيضًا استخدام انتقال إدخال العنصر المشترك
return للعناصر المشتركة. تحدّد عملية نقل المرتجعات كيفية
تنتقل العناصر المشتركة مرة أخرى إلى الجزء السابق عندما
تظهر المعاملة في الحزمة الخلفية. إذا كنت تريد تحديد نوع مختلف من
انتقال إرجاع، فيمكنك القيام بذلك باستخدام
Fragment.setSharedElementReturnTransition()
في طريقة onCreate()
للجزء.
التوافق التنبئي مع الرجوع
يمكنك استخدام ميزة الرجوع التنبؤي مع العديد من الرسوم المتحركة ذات الأجزاء المتقاطعة، ولكن ليس كلها. عند تنفيذ التوقُّع التنبئي مرة أخرى، ضع الاعتبارات التالية في الاعتبار:
- استيراد
Transitions 1.5.0
أو إصدار لاحق وFragments 1.7.0
أو إصدار لاحق - تتوفر الفئة
Animator
والفئات الفرعية ومكتبة AndroidX Transition. - مكتبة
Transition
للفئةAnimation
وإطار العمل غير متاحة. - لا تعمل الصور المتحركة للأجزاء القائمة على التوقّعات إلا على الأجهزة التي تعمل بنظام التشغيل Android 14 أو أعلى.
setCustomAnimations
،setEnterTransition
،setExitTransition
،setReenterTransition
،setReturnTransition
،setSharedElementEnterTransition
وsetSharedElementReturnTransition
مزودًا بظهر تنبؤي.
لمزيد من المعلومات، يُرجى مراجعة إتاحة استخدام الصور المتحركة التي تقترحها الرجوع إلى الصفحة السابقة
تأجيل عمليات النقل
وفي بعض الحالات، قد تحتاج إلى تأجيل انتقال الجزء فترة زمنية قصيرة. على سبيل المثال، قد تحتاج إلى الانتظار حتى يتم عرض جميع في الجزء الذي يتم إدخاله، ويتم قياسه ووضعه حتى يتمكن Android يمكنها تحديد حالتي البداية والنهاية للانتقال بدقة.
بالإضافة إلى ذلك، قد يلزم تأجيل عملية النقل حتى تحميل البيانات الضرورية. على سبيل المثال، قد تحتاج إلى الانتظار حتى تم تحميل من الصور للعناصر المشتركة. وإلا، فقد يكون الانتقال مزعجة في حال انتهاء تحميل صورة أثناء عملية الانتقال أو بعدها.
لتأجيل عملية نقل، يجب أولاً التأكد من أن الجزء
تسمح بإعادة ترتيب تغييرات حالة الأجزاء. للسماح بإعادة الترتيب
تغييرات حالة تجزئة، طلب
FragmentTransaction.setReorderingAllowed()
،
كما هو موضح في المثال التالي:
Kotlin
val fragment = FragmentB() supportFragmentManager.commit { setReorderingAllowed(true) setCustomAnimation(...) addSharedElement(view, view.transitionName) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setReorderingAllowed(true) .setCustomAnimations(...) .addSharedElement(view, view.getTransitionName()) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
لتأجيل انتقال الدخول، اتصل
Fragment.postponeEnterTransition()
في طريقة onViewCreated()
للجزء المُدخل:
Kotlin
class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... postponeEnterTransition() } }
Java
public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... postponeEnterTransition(); } }
بعد تحميل البيانات والاستعداد لبدء عملية النقل، اتصل
Fragment.startPostponedEnterTransition()
يستخدم المثال التالي دالة
مكتبة بالتمرير لتحميل صورة
في ImageView
مشترك، مع تأجيل عملية النقل المقابلة حتى
اكتمل التحميل.
Kotlin
class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... Glide.with(this) .load(url) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(...): Boolean { startPostponedEnterTransition() return false } override fun onResourceReady(...): Boolean { startPostponedEnterTransition() return false } }) .into(headerImage) } }
Java
public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... Glide.with(this) .load(url) .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(...) { startPostponedEnterTransition(); return false; } @Override public boolean onResourceReady(...) { startPostponedEnterTransition(); return false; } }) .into(headerImage) } }
عند التعامل مع حالات مثل بطء اتصال الإنترنت لدى المستخدم، ربما
الحاجة إلى بدء الانتقال المؤجل بعد فترة زمنية معينة بدلاً من
من انتظار تحميل جميع البيانات. في هذه المواقف، يمكنك
الاتصال بدلاً من ذلك
Fragment.postponeEnterTransition(long, TimeUnit)
في طريقة onViewCreated()
للجزء المُدخل، مع مرور المدة
والوحدة الزمنية. ثم يبدأ التأجيل تلقائيًا بعد
انقضى الوقت المحدد.
استخدام انتقالات العناصر المشتركة مع RecyclerView
يجب ألا تبدأ عمليات انتقال الدخول المؤجَّلة قبل أن تظهر كل المشاهدات في صفحة التسجيل
الجزء وقياسه. عند استخدام
RecyclerView
، عليك الانتظار
لأي بيانات لتحميلها ولتكون العناصر الـ RecyclerView
جاهزة للرسم
قبل بدء عملية النقل. وفي ما يلي مثال لذلك:
Kotlin
class FragmentA : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { postponeEnterTransition() // Wait for the data to load viewModel.data.observe(viewLifecycleOwner) { // Set the data on the RecyclerView adapter adapter.setData(it) // Start the transition once all views have been // measured and laid out (view.parent as? ViewGroup)?.doOnPreDraw { startPostponedEnterTransition() } } } }
Java
public class FragmentA extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { postponeEnterTransition(); final ViewGroup parentView = (ViewGroup) view.getParent(); // Wait for the data to load viewModel.getData() .observe(getViewLifecycleOwner(), new Observer<List<String>>() { @Override public void onChanged(List<String> list) { // Set the data on the RecyclerView adapter adapter.setData(it); // Start the transition once all views have been // measured and laid out parentView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw(){ parentView.getViewTreeObserver() .removeOnPreDrawListener(this); startPostponedEnterTransition(); return true; } }); } }); } }
لاحظ أن
ViewTreeObserver.OnPreDrawListener
يتم تعيينها على العنصر الرئيسي لعرض التقسيم. يضمن ذلك أن جميع
على سبيل المثال، تم قياس مشاهدات الأجزاء
وتحديدها، وهي بالتالي جاهزة
قبل بدء انتقال الدخول المؤجل.
وهناك نقطة أخرى يجب مراعاتها عند استخدام انتقالات العناصر المشتركة من خلال
RecyclerView
هو أنه لا يمكنك ضبط اسم انتقال في
تنسيق XML لعنصر واحد (RecyclerView
) بسبب مشاركة عدد عشوائي من العناصر
هذا التخطيط. ويجب تعيين اسم انتقال فريد بحيث
الحركة الانتقالية تستخدم العرض الصحيح.
يمكنك إعطاء كل عنصر مشترك اسم انتقال فريد من خلال
ويتم تعيينها عند ربط ViewHolder
. على سبيل المثال، إذا كانت البيانات الخاصة
لكل عنصر معرفًا فريدًا، ويمكن استخدامه كاسم انتقالي، حيث
كما هو موضح في المثال التالي:
Kotlin
class ExampleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val image = itemView.findViewById<ImageView>(R.id.item_image) fun bind(id: String) { ViewCompat.setTransitionName(image, id) ... } }
Java
public class ExampleViewHolder extends RecyclerView.ViewHolder { private final ImageView image; ExampleViewHolder(View itemView) { super(itemView); image = itemView.findViewById(R.id.item_image); } public void bind(String id) { ViewCompat.setTransitionName(image, id); ... } }
مصادر إضافية
لمزيد من المعلومات حول عمليات نقل الأجزاء، يمكنك الاطّلاع على العناصر الإضافية التالية الموارد.