تخصيص نقل العنصر المشترَك

لتخصيص كيفية تشغيل الحركة المتحركة لانتقال العنصر المشترك، هناك بعض المعلمات التي يمكن استخدامها لتغيير كيفية انتقال العناصر المشتركة.

مواصفات الصور المتحركة

لتغيير مواصفات الصور المتحركة المستخدمة لحركة الحجم والموضع، يمكنك تحديد معلَمة 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.

الشكل 1. مثال يعرض مَعلمات boundsTransform مختلفة

وضع تغيير الحجم

عند إضافة تأثيرات حركية بين حدَّين مشترَكَين، يمكنك ضبط المَعلمة resizeMode على RemeasureToBounds أو ScaleToBounds. تحدد هذه المعلمة كيفية انتقال العنصر المشترك بين الحالتين. تقيس ScaleToBounds أولاً التنسيق الفرعي بقيود العرض الأمامي (أو الاستهداف). ثم يتم تحجيم التخطيط الثابت للطفل ليلائم الحدود المشتركة. يمكن اعتبار ScaleToBounds "مقياسًا رسوميًا" بين الولايات.

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

بالنسبة إلى عناصر Text القابلة للإنشاء، يُنصَح باستخدام ScaleToBounds لأنّه سيتجنّب إعادة تنسيق النص وإعادة تدفقه إلى أسطر مختلفة. بالنسبة إلى الحدود التي تمثل نِسب عرض إلى ارتفاع مختلفة، وإذا كنت تريد استمرارية سلسة بين العنصرين المشترَكين، ننصحك باستخدام السمة RemeasureToBounds.

يمكن رؤية الفرق بين وضعي تغيير الحجم في الأمثلة التالية:

ScaleToBounds

RemeasureToBounds

التخطّي إلى التنسيق النهائي

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

يوضح المثال التالي نص الوصف "Lorem Ipsum" الذي يدخل الشاشة بطريقتين مختلفتين. المثال الأول يتدفق النص أثناء دخوله مع زيادة حجم الحاوية، والمثال الثاني لا تتم إعادة تدفق النص أثناء نموه. تؤدي إضافة Modifier.skipToLookaheadSize() إلى منع إعادة التدفّق أثناء نموه.

No Modifier.skipToLookahead() - لاحظ إعادة تدفق نص "Lorem Ipsum"

Modifier.skipToLookahead() - لاحظ أن نص "Lorem Ipsum" يحافظ على حالته النهائية في بداية الرسوم المتحركة

المقطع والعناصر المركّبة

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

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

بدون "Modifier.renderInSharedTransitionScopeOverlay()"

باستخدام Modifier.renderInSharedTransitionScopeOverlay()

في بعض الأحيان، قد ترغب في جعل عنصرك غير القابل للإنشاء متحركًا وبقائه فوق العناصر الأخرى قبل الانتقال. في مثل هذه الحالات، يمكنك استخدام renderInSharedTransitionScopeOverlay().animateEnterExit() لتحريك العنصر القابل للإنشاء أثناء تشغيل انتقال العنصر المشترك:

JetsnackBottomBar(
    modifier = Modifier
        .renderInSharedTransitionScopeOverlay(
            zIndexInOverlay = 1f,
        )
        .animateEnterExit(
            enter = fadeIn() + slideInVertically {
                it
            },
            exit = fadeOut() + slideOutVertically {
                it
            }
        )
)

الشكل 2.يتحرك شريط التطبيق السفلي للداخل والخارج أثناء انتقالات الصور المتحركة

إذا كنت تريد ألا يتم عرض العنصر الذي تمت مشاركته في تراكب، يمكنك ضبط renderInOverlayDuringTransition على sharedElement() على خطأ.

إشعار التخطيطات التابعة للتغييرات التي تطرأ على حجم العنصر المشترَك

لا يتم تلقائيًا إرسال إشعار إلى sharedBounds() وsharedElement() للحاوية الرئيسية بأي تغييرات في الحجم أثناء انتقالات التنسيق.

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

PlaceholderSize.contentSize (تلقائي)

PlaceholderSize.animatedSize

(لاحظ كيف تتراجع العناصر الأخرى في القائمة استجابةً لتزايد هذا العنصر)