शेयर किए गए एलिमेंट के ट्रांज़िशन को पसंद के मुताबिक बनाएं

शेयर किए गए एलिमेंट के ट्रांज़िशन ऐनिमेशन को पसंद के मुताबिक बनाने के लिए, कुछ पैरामीटर का इस्तेमाल किया जा सकता है. इनकी मदद से, शेयर किए गए एलिमेंट के ट्रांज़िशन के तरीके में बदलाव किया जा सकता है.

ऐनिमेशन की जानकारी

साइज़ और पोज़िशन में बदलाव के लिए इस्तेमाल किए गए ऐनिमेशन स्पेसिफ़िकेशन को बदलने के लिए, Modifier.sharedElement() पर कोई दूसरा boundsTransform पैरामीटर सेट किया जा सकता है. इससे शुरुआती Rect पोज़िशन और टारगेट Rect पोज़िशन की जानकारी मिलती है.

उदाहरण के लिए, ऊपर दिए गए उदाहरण में टेक्स्ट को आर्क मोशन में ले जाने के लिए, keyframes स्पेसिफ़िकेशन का इस्तेमाल करने के लिए, boundsTransform पैरामीटर को सेट करें:

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 का इस्तेमाल उन बाउंड के लिए किया जाता है जिनकी चौड़ाई-ऊंचाई का अनुपात अलग-अलग होता है. साथ ही, इसका इस्तेमाल तब भी किया जाता है, जब आपको शेयर किए गए दो एलिमेंट के बीच फ़्लूड ट्रांज़िशन चाहिए होता है.

रीसाइज़ करने के दोनों मोड के बीच का अंतर, यहां दिए गए उदाहरणों में देखा जा सकता है:

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
)

अगर आपको यह पक्का करना है कि शेयर किया गया कोई एलिमेंट, पैरंट कंटेनर के बाहर कभी रेंडर न हो, तो sharedElement() पर clipInOverlayDuringTransition सेट किया जा सकता है. डिफ़ॉल्ट रूप से, नेस्ट किए गए शेयर किए गए बाउंड के लिए, 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
            }
        )
)

दूसरी इमेज. ऐनिमेशन ट्रांज़िशन के दौरान, बॉटम ऐप्लिकेशन बार स्लाइड इन और आउट हो रहा है.

अगर आपको शेयर किए गए एलिमेंट को ओवरले में रेंडर नहीं करना है, तो sharedElement() पर renderInOverlayDuringTransition को फ़ॉल्स पर सेट करें.

शेयर किए गए एलिमेंट के साइज़ में हुए बदलावों के बारे में, मिलते-जुलते लेआउट को सूचना दें

डिफ़ॉल्ट रूप से, लेआउट ट्रांज़िशन के दौरान साइज़ में होने वाले बदलावों के बारे में sharedBounds() और sharedElement(), पैरंट कंटेनर को सूचना नहीं देते हैं.

ट्रांज़िशन के दौरान, साइज़ में हुए बदलावों को पैरंट कंटेनर में लागू करने के लिए, placeHolderSize पैरामीटर को PlaceHolderSize.animatedSize में बदलें. ऐसा करने से, आइटम का साइज़ बढ़ता या घटता है. लेआउट में मौजूद अन्य सभी आइटम, बदलाव के हिसाब से काम करते हैं.

PlaceholderSize.contentSize (डिफ़ॉल्ट)

PlaceholderSize.animatedSize

(ध्यान दें कि एक आइटम के बढ़ने पर, सूची में मौजूद अन्य आइटम नीचे की ओर चले जाते हैं)