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

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

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

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

لا يتوفّر Modifier.skipToLookahead()‎ - يُرجى ملاحظة إعادة تدفق نص "Lorem Ipsum"

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

المقاطع والعناصر التي تظهر فوق المحتوى

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

سيتم عرض العنصر فوق عناصر واجهة المستخدم الأخرى غير المشتركة، وبعد اكتمال عملية النقل، سيتم إسقاط العنصر من التراكب إلى 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(). بشكلٍ default، بالنسبة إلى الحدود المشترَكة المُدمَجة، يستخدم 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() على false.

إشعار التنسيقات الشقيقة بالتغييرات في حجم العنصر المشترَك

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

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

PlaceholderSize.contentSize (تلقائي)

PlaceholderSize.animatedSize

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