لتخصيص طريقة تشغيل تأثيرات الحركة في انتقال العناصر المشترَكة، هناك بعض المَعلمات التي يمكن استخدامها لتغيير طريقة انتقال العناصر المشترَكة.
مواصفات الصورة المتحركة
لتغيير مواصفات الصور المتحركة المستخدَمة لحركة الحجم والموضع، يمكنك
تحديد مَعلمة boundsTransform مختلفة في Modifier.sharedElement().
يوفّر ذلك الموضع الأولي لـ Rect والموضع المستهدَف لـ Rect.
على سبيل المثال، لجعل النص في المثال السابق يتحرك بحركة قوسية، حدِّد المَعلمة boundsTransform لاستخدام مواصفات keyframes:
val textBoundsTransform = BoundsTransform { initialBounds, targetBounds -> keyframes { durationMillis = boundsAnimationDurationMillis initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing targetBounds at boundsAnimationDurationMillis } } Text( "Cupcake", fontSize = 28.sp, modifier = Modifier.sharedBounds( rememberSharedContentState(key = "title"), animatedVisibilityScope = animatedVisibilityScope, boundsTransform = textBoundsTransform ) )
يمكنك استخدام أي AnimationSpec. يستخدم هذا المثال مواصفات keyframes.
boundsTransform مختلفةوضع تغيير الحجم
عند إنشاء حركة بين حدود مشتركة، يمكنك ضبط المَعلمة resizeMode
على RemeasureToBounds أو ScaleToBounds. تحدّد هذه المَعلمة كيفية انتقال العنصر المشترَك بين الحالتَين. يقيس ScaleToBounds أولاً
تنسيق العناصر الثانوية باستخدام قيود الاستباق (أو الاستهداف). بعد ذلك، يتم تغيير حجم التنسيق الثابت للعنصر الفرعي ليلائم الحدود المشتركة.
يمكن اعتبار ScaleToBounds "مقياسًا بيانيًا" بين الولايات.
في المقابل، تعيد دالة RemeasureToBounds قياس تنسيق العنصر الفرعي لـ sharedBounds وإعادة تنسيقه باستخدام قيود ثابتة متحركة استنادًا إلى الحجم المستهدف. يتم تشغيل إعادة القياس من خلال تغيير حجم الحدود، والذي يمكن أن يكون في كل إطار.
بالنسبة إلى الدوال المركّبة Text، يُنصح باستخدام ScaleToBounds لأنّها تتجنّب إعادة التنسيق وإعادة تدفق النص إلى أسطر مختلفة. يُنصح باستخدام RemeasureToBounds للحدود التي تختلف فيها نِسب العرض إلى الارتفاع، وإذا كنت تريد استمرارية سلسة بين العنصرَين المشتركَين.
يمكن ملاحظة الفرق بين وضعَي تغيير الحجم في الأمثلة التالية:
|
|
|---|---|
تفعيل العناصر المشتركة وإيقافها ديناميكيًا
يتم ضبط sharedElement() وsharedBounds() تلقائيًا لتحريك تغييرات التنسيق كلما تم العثور على مفتاح مطابق في الحالة المستهدفة. ومع ذلك،
قد ترغب في إيقاف هذه الحركة ديناميكيًا استنادًا إلى شروط معيّنة،
مثل اتجاه التنقّل أو حالة واجهة المستخدم الحالية.
للتحكّم في حدوث انتقال العناصر المشتركة، يمكنك تخصيص
SharedContentConfig الذي تم تمريره إلى rememberSharedContentState(). تحدّد السمة isEnabled ما إذا كان العنصر المشترَك نشطًا.
يوضّح المثال التالي كيفية تحديد إعدادات تفعّل الانتقال المشترك فقط عند التنقّل بين شاشات معيّنة (مثلاً، من "أ" إلى "ب" فقط)، مع إيقافه للشاشات الأخرى.
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
بشكل تلقائي، إذا تم إيقاف عنصر مشترك أثناء حركة جارية، فإنه
يستمر في إكمال الحركة الحالية قيد التقدم لمنع إزالة الحركات أثناء التشغيل
عن طريق الخطأ. إذا كنت بحاجة إلى إزالة العنصر أثناء
تشغيل الحركة، يمكنك إلغاء
shouldKeepEnabledForOngoingAnimation في واجهة SharedContentConfig
لإرجاع القيمة false.
التخطّي إلى التنسيق النهائي
عند الانتقال بين تنسيقَين، يتم تلقائيًا تحريك حجم التنسيق بين حالتَي البداية والنهاية. قد يكون هذا سلوكًا غير مرغوب فيه عند تحريك محتوى مثل النص.
يوضح المثال التالي نص الوصف "Lorem Ipsum" الذي يدخل إلى الشاشة بطريقتين مختلفتين. في المثال الأول، تتم إعادة تدفق النص أثناء دخوله مع زيادة حجم الحاوية. في المثال الثاني، لا يتدفق النص
مرة أخرى أثناء نموه. تؤدي إضافة Modifier.skipToLookaheadSize() إلى منع إعادة التدفق
أثناء نموه.
بدون |
|
|---|---|
المقاطع والعناصر التي تظهر فوق المحتوى
لكي تتم مشاركة العناصر المشتركة بين الدوال المركّبة المختلفة، يتم رفع مستوى عرض الدالة المركّبة إلى طبقة تراكب عند بدء الانتقال إلى العنصر المطابق في الوجهة. يؤدي ذلك إلى تجاوز حدود العنصر الرئيسي وتحويلات الطبقة (على سبيل المثال، ألفا والمقياس).
وسيتم عرضه فوق عناصر واجهة المستخدم الأخرى غير المشتركة. بعد انتهاء عملية النقل، سيتم نقل العنصر من النافذة المرافقة إلى DrawScope الخاص به.
لاقتصاص عنصر مشترَك في شكل معيّن، استخدِم دالة Modifier.clip() العادية. ضَعها بعد sharedElement():
Image( painter = painterResource(id = R.drawable.cupcake), contentDescription = "Cupcake", modifier = Modifier .size(100.dp) .sharedElement( rememberSharedContentState(key = "image"), animatedVisibilityScope = this@AnimatedContent ) .clip(RoundedCornerShape(16.dp)), contentScale = ContentScale.Crop )
إذا أردت التأكّد من أنّ العنصر المشترَك لا يتم عرضه خارج حاوية رئيسية، يمكنك ضبط clipInOverlayDuringTransition على sharedElement(). بشكل تلقائي، بالنسبة إلى الحدود المشتركة المتداخلة، يستخدم clipInOverlayDuringTransition مسار القطع من العنصر الرئيسي sharedBounds().
لإبقاء عناصر معيّنة في واجهة المستخدم، مثل الشريط السفلي أو زر الإجراء الرئيسي، في الأعلى دائمًا أثناء انتقال العناصر المشتركة، استخدِم Modifier.renderInSharedTransitionScopeOverlay(). بشكل تلقائي، يحافظ هذا المُعدِّل على المحتوى في التراكب خلال فترة نشاط الانتقال المشترك.
على سبيل المثال، في Jetsnack، يجب وضع BottomAppBar فوق العنصر المشترك إلى أن تصبح الشاشة غير مرئية. تؤدي إضافة المُعدِّل إلى الدالة المركّبة إلى إبقائها في الأعلى.
بدون |
باستخدام |
|---|---|
قد ترغب في أن تتحرك الدالة المركّبة غير المشتركة بعيدًا بالإضافة إلى
البقاء في أعلى الدوال المركّبة الأخرى قبل الانتقال. في هذه الحالات، استخدِم renderInSharedTransitionScopeOverlay().animateEnterExit() لتحريك الدالة المركّبة أثناء تشغيل عملية انتقال العناصر المشترَكة:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
في حالات نادرة، إذا أردت عدم عرض العنصر المشترك في
تراكب، يمكنك ضبط renderInOverlayDuringTransition على sharedElement()
على "خطأ".
إرسال إشعارات إلى التنسيقات المجاورة بشأن التغييرات في حجم العنصر المشترَك
لا تُرسل السمتان sharedBounds() وsharedElement() إشعارًا إلى الحاوية الرئيسية بأي تغييرات في الحجم أثناء انتقال التنسيق، وذلك بشكل تلقائي.
لنشر تغييرات الحجم إلى الحاوية الرئيسية أثناء انتقالها،
يُرجى تغيير المَعلمة placeholderSize إلى PlaceholderSize.AnimatedSize. يؤدي القيام بذلك إلى نمو العنصر أو تقلصه. تستجيب جميع العناصر الأخرى في التخطيط
للتغيير.
|
(لاحظ كيف تتحرك العناصر الأخرى في القائمة لأسفل استجابةً لنمو العنصر الواحد) |
|---|---|