أخطاء خفية مع انتقالات العناصر المشتركة



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

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

ابدأ


قبل القيام بالرسوم المتحركة ، قرأت العشرات من المقالات ولكن معظمها كان حول نشاط الانتقال. ومع ذلك ، فقد صادفت ملاحظات جيدة حول Fragments وأريد أن أعطي القليل من المعلومات حول كيفية إنشاء Shared Element Transition.

فيما يلي الخطوات الرئيسية لإنشاء الرسوم المتحركة:

  1. تمكين setReorderingAllowed(true) . يسمح بإعادة ترتيب أساليب دورة الحياة وسيتم عرض الرسوم المتحركة بشكل صحيح.
  2. استدعاء addSharedElement() وإضافة طرق العرض التي ستتم مشاركتها بين الشاشات
  3. أضف android:transitionName فريدًا من نوعه android:transitionName
  4. إضافة sharedElementEnterTransition/sharedElementReturnTransition في جزء الوجهة. اختياريا: للحصول على تأثير أفضل ، يمكننا أيضًا ضبط enterTransition/exitTransition .
  5. إضافة postponeEnterTransition/startPostponedEnterTransition لتحديد اللحظة التي يتم فيها تحميل البيانات وتكون واجهة المستخدم جاهزة postponeEnterTransition/startPostponedEnterTransition

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

الرسوم المتحركة المكسورة


هذا ليس ما توقعناه. دعونا معرفة ذلك.

خطأ # 1. انتقال ثابتالأسماء (نصف يوم يضيع)


كما قلت من قبل ، يجب أن يكون لآرائنا أسماء انتقال فريدة - وإلا فلن يتمكن إطار الانتقال من التعرف على طريقة العرض التي تشارك في عملية النقل وستجعلها بدونها. إذن أين المشكلة؟

الشيء هو RecyclerView. هذا كل شيء.

إذا كان هناك RecyclerView وكانت طريقة العرض المتحركة جزءًا من عنصر RecyclerView ، فيجب عليك إنشاء وضبط اسم transitionName بشكل حيوي (نسيان XML). علاوة على ذلك ، يجب أن تفعل ذلك في كلا الشظايا حتى إذا لم يكن لدى الثانية RecyclerView.

لذلك الإصلاح هو:

 val transitionNameImage = context.getString(R.string.transition_image, title) 

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

خطأ # 2. لا تفكر في شظية الوالدين (يضيع 1.5 يوم)


أنا أعرف ، قد تسأل "كيف تأتي؟" لكن عندما كنت أقرأ المقالات حول الرسوم المتحركة المشتركة ، لم يكن أي شخص يعتبر مثالاً في التسلسل الهرمي للجزء المعقد. لهذا السبب قد لا تهتم به في بعض الأحيان.

لذلك ، كانت postponeEnterTransition()/startPostponedEnterTransition() الأولى تابعة لحاوية القطعة ولا عجب في أن postponeEnterTransition()/startPostponedEnterTransition() لم يكن له أي تأثير.

ها هو ذا
 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) parentFragment?.also { parentFragment -> NewsTransitioner.setupFirstFragment(parentFragment) parentFragment.postponeEnterTransition() } // Initialization UI } 


ما عليك القيام به هنا هو استدعاء هذه الأساليب من جزء الأصل.

خطأ # 3. التقليل من الإنزلاق (يضيع يومين)


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

حسنا كنت مخطئا. ربما هذا هو الخطأ الأكثر صعوبة الذي واجهته. دعنا نلقي نظرة على ما لدينا حتى الآن:

الرسوم المتحركة الحالية


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

لا أريد أن أصف التحقيق بأكمله هنا. قصة قصيرة طويلة ، كنت محظوظاً لأنني أتعثر على مقال لطيف .

حيث وجدت الحل. ومن هنا:
"لدينا هذا الخلل لأن Glide يحاول تحسين تحميل الصور. بشكل افتراضي ، يقوم Glide بتغيير حجم الصور وتقليصها لتتناسب مع العرض الهدف. "

لإصلاحها ، أضفت ، لا نكت ، سطر واحد من التعليمات البرمجية مثل هذا لتهيئة سلسلة Glide:

 Glide .with(target) .load(url) .apply( RequestOptions().dontTransform() // this line ) 

لذلك ، يجب عليك تعطيل أي تحويلات Glide على الصور إذا كانت متورطة في انتقال مشترك.

خطأ # 4. إدارة postPostponeTransition () بشكل غير صحيح


بصراحة ، إنه ليس خطأ بالضبط ولكن ما زلت أظن أنه سيكون من الجيد ذكره.

عندما يتعلق الأمر بإدارة postPostponeTransition() و startPostponedEnterTransition() ، يجب عليك تحديد اللحظة المناسبة. اللحظة هي عندما يتم بالفعل رسم واجهة المستخدم.

هناك نقطتان أساسيتان يجب أن نعرفهما قبل استدعاء الطرق:

  • من ناحية ، عندما يتم تحميل الصور التي تمر بمرحلة انتقالية وجاهزة
  • من ناحية أخرى ، يتم قياس التسلسل الهرمي وجهات النظر ووضعها

للصور عادة نستخدم Glide وله مستمع رائع:

 RequestListener<Drawable> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean ): Boolean { startPostponedEnterTransition() return false } override fun onResourceReady( resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { startPostponedEnterTransition() return false } } 

لاحظ أننا نسمي startPostponedEnterTransition() في كلتا الحالتين: النجاح والخطأ. إنه أمر حيوي لأنه إذا لم نجعله سيتم تجميد التطبيق الخاص بك.

في الحالات التي تأتي فيها عملية النقل دون أي صور ، يمكنك استخدام طريقة امتداد doOnPreDraw() من ktx على مخطط الجذر والقيام startPostponedEnterTransition() هناك.

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

وضع كل ذلك معا


لقد أوضحت في هذه المقالة بعض المشكلات التي قد تواجهها في تنفيذ عملية انتقال مشتركة مع أجزاء وطرق التعامل معها.

باختصار ، ها هم:

  1. ضع في اعتبارك التسلسل الهرمي للشظايا (لا تنسى عن جزء الأصل)
  2. في حالة استخدام RecyclerView ، قم دائمًا بإنشاء أسماء انتقال بشكل ديناميكي (المصدر + الوجهة)
  3. تعطيل أي تحولات الإنزلاق
  4. قم بإجراء مكالمات postPostponeTransition() و startPostponedEnterTransition() بشكل صحيح فيما يتعلق startPostponedEnterTransition() .

الرسوم المتحركة النهائية


شكرا لك على القراءة ونراكم في المرة القادمة!

ملاحظة: إذا كنت تتساءل عن كيفية تحريك زوايا الصورة ، فإليك الكود ، أضف فقط إلى بقية تحركات الرسوم المتحركة المشتركة.

مثال
 fragment.sharedElementEnterTransition = TransitionSet().apply { addTransition(ChangeImageTransform()) addTransition(ChangeBounds()) addTransition(ChangeTransform()) addTransition(ChangeOutlineRadiusTransition(animationRadiusData.startRadius, animationRadiusData.endRadius) ) } 

Source: https://habr.com/ru/post/ar463459/


All Articles