لتخصيص طريقة تشغيل تأثيرات الحركة في انتقال العناصر المشترَكة، هناك بعض المَعلمات التي يمكن استخدامها لتغيير طريقة انتقال العناصر المشترَكة.
مواصفات الصورة المتحركة
لتغيير مواصفات الحركة المستخدَمة في حركة الحجم والموضع، يمكنك
تحديد مَعلمة 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
على SharedTransitionScope.ResizeMode.RemeasureToBounds أو
SharedTransitionScope.ResizeMode.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 } } } } }
By default, if a shared element is disabled during an ongoing animation, it
still completes the current in-progress animation to prevent accidentally
removing in-flight animations. إذا كنت بحاجة إلى إزالة العنصر أثناء
تنفيذ الحركة، يمكنك إلغاء
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(). By
default, for nested shared bounds, clipInOverlayDuringTransition uses the clip
path from the parent 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. يؤدي القيام بذلك إلى نمو العنصر أو تقلصه. تستجيب جميع العناصر الأخرى في التخطيط
للتغيير.
|
(لاحظ كيف تتحرك العناصر الأخرى في القائمة لأسفل استجابةً لنمو العنصر الواحد) |
|---|---|