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

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

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

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

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

ScaleToBounds

RemeasureToBounds

सीधे फ़ाइनल लेआउट पर जाएं

डिफ़ॉल्ट रूप से, दो लेआउट के बीच ट्रांज़िशन करते समय, लेआउट का साइज़ शुरू और आखिरी स्थिति के बीच ऐनिमेशन के साथ बदलता है. टेक्स्ट जैसे कॉन्टेंट को ऐनिमेट करते समय, ऐसा करना ठीक नहीं है.

नीचे दिए गए उदाहरण में, ब्यौरे का टेक्स्ट "Lorem Ipsum", स्क्रीन पर दो अलग-अलग तरीकों से दिख रहा है. पहले उदाहरण में, कंटेनर के साइज़ में बढ़ोतरी होने पर टेक्स्ट फिर से फ़्लो करता है. वहीं, दूसरे उदाहरण में, टेक्स्ट के बढ़ने पर फिर से फ़्लो नहीं होता. Modifier.skipToLookaheadSize() जोड़ने से, डेटा बढ़ने पर रीफ़्लो को रोका जा सकता है.

बिना 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
            }
        )
)

दूसरी इमेज.ऐनिमेशन ट्रांज़िशन के दौरान, बॉटम ऐप्लिकेशन बार के अंदर और बाहर स्लाइड करने की सुविधा

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

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

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

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

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

PlaceholderSize.animatedSize

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