कंपोज़ में शेयर किए गए एलिमेंट का ट्रांज़िशन

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

उदाहरण के लिए, इस वीडियो में, लिस्टिंग पेज से लेकर ज़्यादा जानकारी वाले पेज तक, शेयर किए गए स्नैक की इमेज और टाइटल देखा जा सकता है.

पहली इमेज. JetSnacks के शेयर किए गए एलिमेंट का डेमो

Compose में कुछ हाई लेवल एपीआई हैं जो शेयर किए जाने वाले एलिमेंट बनाने में आपकी मदद करते हैं:

  • SharedTransitionLayout: शेयर किए गए एलिमेंट ट्रांज़िशन को लागू करने के लिए, सबसे बाहरी लेआउट की ज़रूरत होती है. इससे SharedTransitionScope मिलता है. शेयर किए गए एलिमेंट के मॉडिफ़ायर का इस्तेमाल करने के लिए, कॉम्पोज़ेबल को SharedTransitionScope में होना चाहिए.
  • Modifier.sharedElement(): यह एक ऐसा मॉडिफ़ायर है जो SharedTransitionScope उस कॉम्पोज़ेबल को फ़्लैग करता है जिसे किसी दूसरे कॉम्पोज़ेबल से मैच करना है.
  • Modifier.sharedBounds(): वह मॉडिफ़ायर जो SharedTransitionScope को फ़्लैग करता है, तो इस कंपोज़ेबल के बाउंड का इस्तेमाल कंटेनर बाउंड के तौर पर किया जाना चाहिए. इससे, यह तय किया जा सकेगा कि ट्रांज़िशन कहां होना चाहिए. sharedElement() के मुकाबले, sharedBounds() को अलग-अलग तरह के विज़ुअल वाले कॉन्टेंट के लिए डिज़ाइन किया गया है.

कंपोज़ में शेयर किए गए एलिमेंट बनाते समय एक अहम बात यह है कि वे ओवरले और क्लिपिंग के साथ कैसे काम करते हैं. इस अहम विषय के बारे में ज़्यादा जानने के लिए, क्लिपिंग और ओवरले सेक्शन पर नज़र डालें.

बुनियादी इस्तेमाल

इस सेक्शन में, नीचे दिया गया ट्रांज़िशन बनाया जाएगा. इसमें छोटे "सूची" आइटम से बड़े और ज़्यादा जानकारी वाले आइटम पर ट्रांज़िशन किया जाएगा:

दूसरी इमेज. दो कंपोज़ेबल के बीच शेयर किए गए एलिमेंट के ट्रांज़िशन का सामान्य उदाहरण.

Modifier.sharedElement() का इस्तेमाल करने का सबसे अच्छा तरीका AnimatedContent, AnimatedVisibility या NavHost के साथ इस्तेमाल करना है, क्योंकि इससे कंपोज़ेबल के बीच ट्रांज़िशन को अपने-आप मैनेज किया जा सकता है.

शुरुआत में, शेयर किए गए एलिमेंट जोड़ने से पहले, एक मौजूदा बुनियादी AnimatedContent होता है, जिसमें MainContent और DetailsContent कॉम्पोज़ेबल होता है:

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

  1. शेयर किए गए एलिमेंट को दो लेआउट के बीच ऐनिमेट करने के लिए, SharedTransitionLayout की मदद से कंपोज़ेबल AnimatedContent के आस-पास डालें. SharedTransitionLayout और AnimatedContent के स्कोप, MainContent और DetailsContent को पास किए जाते हैं:

    var showDetails by remember {
        mutableStateOf(false)
    }
    SharedTransitionLayout {
        AnimatedContent(
            showDetails,
            label = "basic_transition"
        ) { targetState ->
            if (!targetState) {
                MainContent(
                    onShowDetails = {
                        showDetails = true
                    },
                    animatedVisibilityScope = this@AnimatedContent,
                    sharedTransitionScope = this@SharedTransitionLayout
                )
            } else {
                DetailsContent(
                    onBack = {
                        showDetails = false
                    },
                    animatedVisibilityScope = this@AnimatedContent,
                    sharedTransitionScope = this@SharedTransitionLayout
                )
            }
        }
    }

  2. मैच करने वाले दो कॉम्पोज़ेबल पर, अपनी कॉम्पोज़ेबल मॉडिफ़ायर चेन में Modifier.sharedElement() जोड़ें. SharedContentState ऑब्जेक्ट बनाएं और इसे rememberSharedContentState() से याद रखें. SharedContentState ऑब्जेक्ट, यूनीक कुंजी को सेव कर रहा है. इससे, शेयर किए गए एलिमेंट तय होते हैं. कॉन्टेंट की पहचान करने के लिए कोई यूनीक कुंजी दें और आइटम को याद रखने के लिए rememberSharedContentState() का इस्तेमाल करें. AnimatedContentScope को मॉडिफ़ायर में पास किया जाता है. इसका इस्तेमाल, ऐनिमेशन को कंट्रोल करने के लिए किया जाता है.

    @Composable
    private fun MainContent(
        onShowDetails: () -> Unit,
        modifier: Modifier = Modifier,
        sharedTransitionScope: SharedTransitionScope,
        animatedVisibilityScope: AnimatedVisibilityScope
    ) {
        Row(
            // ...
        ) {
            with(sharedTransitionScope) {
                Image(
                    painter = painterResource(id = R.drawable.cupcake),
                    contentDescription = "Cupcake",
                    modifier = Modifier
                        .sharedElement(
                            rememberSharedContentState(key = "image"),
                            animatedVisibilityScope = animatedVisibilityScope
                        )
                        .size(100.dp)
                        .clip(CircleShape),
                    contentScale = ContentScale.Crop
                )
                // ...
            }
        }
    }
    
    @Composable
    private fun DetailsContent(
        modifier: Modifier = Modifier,
        onBack: () -> Unit,
        sharedTransitionScope: SharedTransitionScope,
        animatedVisibilityScope: AnimatedVisibilityScope
    ) {
        Column(
            // ...
        ) {
            with(sharedTransitionScope) {
                Image(
                    painter = painterResource(id = R.drawable.cupcake),
                    contentDescription = "Cupcake",
                    modifier = Modifier
                        .sharedElement(
                            rememberSharedContentState(key = "image"),
                            animatedVisibilityScope = animatedVisibilityScope
                        )
                        .size(200.dp)
                        .clip(CircleShape),
                    contentScale = ContentScale.Crop
                )
                // ...
            }
        }
    }

यह जानने के लिए कि शेयर किए गए एलिमेंट का मैच हुआ है या नहीं, rememberSharedContentState() को वैरिएबल में एक्सट्रैक्ट करें और isMatchFound से क्वेरी करें.

जिसके कारण नीचे दिए गए अपने आप चलने वाले ऐनिमेशन होते हैं:

चौथी इमेज. दो कॉम्पोज़ेबल के बीच शेयर किए गए एलिमेंट के ट्रांज़िशन का बुनियादी उदाहरण.

आप देख सकते हैं कि पूरे कंटेनर के बैकग्राउंड का रंग और साइज़, अब भी AnimatedContent की डिफ़ॉल्ट सेटिंग का इस्तेमाल करता है.

शेयर की गई सीमाएं बनाम शेयर किए गए एलिमेंट

Modifier.sharedBounds(), Modifier.sharedElement() से मिलता-जुलता है. हालांकि, मॉडिफ़ायर इस तरह से अलग-अलग होते हैं:

  • sharedBounds() का मतलब ऐसे कॉन्टेंट के लिए है जो दिखने में अलग-अलग है, लेकिन राज्यों के बीच का हिस्सा एक ही होना चाहिए, जबकि sharedElement() के लिए कॉन्टेंट एक जैसा होना चाहिए.
  • sharedBounds() में, स्क्रीन पर जाने और बाहर जाने वाला कॉन्टेंट दो राज्यों के बीच ट्रांज़िशन के दौरान दिखता है, जबकि sharedElement() में, सिर्फ़ टारगेट किया गया कॉन्टेंट, बदलाव वाली सीमाओं में रेंडर होता है. Modifier.sharedBounds() में enter और exit पैरामीटर होते हैं. इनसे यह तय किया जाता है कि कॉन्टेंट को कैसे ट्रांज़िशन करना है. यह ठीक वैसा ही है जैसे AnimatedContent काम करता है.
  • sharedBounds() के लिए, कंटेनर ट्रांसफ़ॉर्म पैटर्न का इस्तेमाल सबसे ज़्यादा किया जाता है. वहीं, sharedElement() के लिए, हीरो ट्रांज़िशन का इस्तेमाल किया जाता है.
  • Text कॉम्पोज़ेबल का इस्तेमाल करते समय, फ़ॉन्ट में बदलाव करने के लिए sharedBounds() का इस्तेमाल करना बेहतर होता है. जैसे, इटैलिक और बोल्ड के बीच ट्रांज़िशन करना या रंग में बदलाव करना.

पिछले उदाहरण में, दो अलग-अलग स्थितियों में Row और Column में Modifier.sharedBounds() जोड़ने से, हमें दोनों के बाउंड शेयर करने और ट्रांज़िशन ऐनिमेशन करने की अनुमति मिलेगी. इससे, दोनों के बीच का फ़ासला बढ़ जाएगा:

@Composable
private fun MainContent(
    onShowDetails: () -> Unit,
    modifier: Modifier = Modifier,
    sharedTransitionScope: SharedTransitionScope,
    animatedVisibilityScope: AnimatedVisibilityScope
) {
    with(sharedTransitionScope) {
        Row(
            modifier = Modifier
                .padding(8.dp)
                .sharedBounds(
                    rememberSharedContentState(key = "bounds"),
                    animatedVisibilityScope = animatedVisibilityScope,
                    enter = fadeIn(),
                    exit = fadeOut(),
                    resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds()
                )
                // ...
        ) {
            // ...
        }
    }
}

@Composable
private fun DetailsContent(
    modifier: Modifier = Modifier,
    onBack: () -> Unit,
    sharedTransitionScope: SharedTransitionScope,
    animatedVisibilityScope: AnimatedVisibilityScope
) {
    with(sharedTransitionScope) {
        Column(
            modifier = Modifier
                .padding(top = 200.dp, start = 16.dp, end = 16.dp)
                .sharedBounds(
                    rememberSharedContentState(key = "bounds"),
                    animatedVisibilityScope = animatedVisibilityScope,
                    enter = fadeIn(),
                    exit = fadeOut(),
                    resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds()
                )
                // ...

        ) {
            // ...
        }
    }
}

पांचवी इमेज. दो कंपोज़ेबल के बीच शेयर की गई सीमाएं.

दायरों को समझें

Modifier.sharedElement() का इस्तेमाल करने के लिए, कंपोज़ेबल को SharedTransitionScope में होना चाहिए. SharedTransitionLayout कॉम्पोज़ेबल, SharedTransitionScope उपलब्ध कराता है. पक्का करें कि आपने अपने यूज़र इंटरफ़ेस (यूआई) की हैरारकी में, एलिमेंट को उसी टॉप-लेवल पर रखा हो जिसे आपको शेयर करना है.

आम तौर पर, कॉम्पोज़ेबल को भी AnimatedVisibilityScope में रखा जाना चाहिए. आम तौर पर, यह वैल्यू AnimatedContent का इस्तेमाल करके, कंपोज़ेबल के बीच स्विच करने या AnimatedVisibility का इस्तेमाल करते समय दी जाती है. इसके अलावा, NavHost कंपोज़ेबल फ़ंक्शन की मदद से ऐसा किया जाता है. ऐसा तब तक किया जाता है, जब तक मैन्युअल तरीके से विज़िबिलिटी मैनेज नहीं की जाती. एक से ज़्यादा स्कोप इस्तेमाल करने के लिए, ज़रूरी स्कोप को CompositionLocal में सेव करें. इसके अलावा, Kotlin में कॉन्टेक्स्ट रिसीवर का इस्तेमाल करें या अपने फ़ंक्शन में स्कोप को पैरामीटर के तौर पर पास करें.

CompositionLocals का इस्तेमाल तब करें, जब आपके पास ट्रैक करने के लिए एक से ज़्यादा स्कोप हों या नेस्ट की गई हैरारकी का क्रम बहुत गहरा हो. CompositionLocal की मदद से, यह चुना जा सकता है कि डेटा को सेव और इस्तेमाल करने के लिए किन सटीक स्कोप का इस्तेमाल किया जाए. वहीं दूसरी ओर, जब कॉन्टेक्स्ट रिसीवर का इस्तेमाल किया जाता है, तो आपकी हैरारकी में मौजूद अन्य लेआउट, दिए गए स्कोप को गलती से बदल सकते हैं. उदाहरण के लिए, अगर आपके पास नेस्ट किए गए कई AnimatedContent हैं, तो स्कोप को बदला जा सकता है.

val LocalNavAnimatedVisibilityScope = compositionLocalOf<AnimatedVisibilityScope?> { null }
val LocalSharedTransitionScope = compositionLocalOf<SharedTransitionScope?> { null }

@Composable
private fun SharedElementScope_CompositionLocal() {
    // An example of how to use composition locals to pass around the shared transition scope, far down your UI tree.
    // ...
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this
        ) {
            // This could also be your top-level NavHost as this provides an AnimatedContentScope
            AnimatedContent(state, label = "Top level AnimatedContent") { targetState ->
                CompositionLocalProvider(LocalNavAnimatedVisibilityScope provides this) {
                    // Now we can access the scopes in any nested composables as follows:
                    val sharedTransitionScope = LocalSharedTransitionScope.current
                        ?: throw IllegalStateException("No SharedElementScope found")
                    val animatedVisibilityScope = LocalNavAnimatedVisibilityScope.current
                        ?: throw IllegalStateException("No AnimatedVisibility found")
                }
                // ...
            }
        }
    }
}

इसके अलावा, अगर आपका क्रम गहराई से नेस्ट नहीं किया गया है, तो स्कोप डाउन को पैरामीटर के तौर पर पास किया जा सकता है:

@Composable
fun MainContent(
    animatedVisibilityScope: AnimatedVisibilityScope,
    sharedTransitionScope: SharedTransitionScope
) {
}

@Composable
fun Details(
    animatedVisibilityScope: AnimatedVisibilityScope,
    sharedTransitionScope: SharedTransitionScope
) {
}

AnimatedVisibility के साथ शेयर किए गए एलिमेंट

पिछले उदाहरणों में AnimatedContent के साथ शेयर किए गए एलिमेंट को इस्तेमाल करने का तरीका दिखाया गया था, लेकिन शेयर किए गए एलिमेंट AnimatedVisibility के साथ भी काम करते हैं.

उदाहरण के लिए, लेज़ी ग्रिड के इस उदाहरण में हर एलिमेंट को AnimatedVisibility में रैप किया गया है. आइटम पर क्लिक करने पर, कॉन्टेंट को यूज़र इंटरफ़ेस (यूआई) से बाहर खींचकर, डायलॉग जैसे कॉम्पोनेंट में ले जाया जाता है.

var selectedSnack by remember { mutableStateOf<Snack?>(null) }

SharedTransitionLayout(modifier = Modifier.fillMaxSize()) {
    LazyColumn(
        // ...
    ) {
        items(listSnacks) { snack ->
            AnimatedVisibility(
                visible = snack != selectedSnack,
                enter = fadeIn() + scaleIn(),
                exit = fadeOut() + scaleOut(),
                modifier = Modifier.animateItem()
            ) {
                Box(
                    modifier = Modifier
                        .sharedBounds(
                            sharedContentState = rememberSharedContentState(key = "${snack.name}-bounds"),
                            // Using the scope provided by AnimatedVisibility
                            animatedVisibilityScope = this,
                            clipInOverlayDuringTransition = OverlayClip(shapeForSharedElement)
                        )
                        .background(Color.White, shapeForSharedElement)
                        .clip(shapeForSharedElement)
                ) {
                    SnackContents(
                        snack = snack,
                        modifier = Modifier.sharedElement(
                            state = rememberSharedContentState(key = snack.name),
                            animatedVisibilityScope = this@AnimatedVisibility
                        ),
                        onClick = {
                            selectedSnack = snack
                        }
                    )
                }
            }
        }
    }
    // Contains matching AnimatedContent with sharedBounds modifiers.
    SnackEditDetails(
        snack = selectedSnack,
        onConfirmClick = {
            selectedSnack = null
        }
    )
}

छठी इमेज.AnimatedVisibility के साथ शेयर किए गए एलिमेंट.

संशोधक ऑर्डरिंग

Modifier.sharedElement() और Modifier.sharedBounds() के साथ, आपके बदलाव करने वाले निर्देश की चेन का क्रम मायने रखता है, ठीक वैसे ही जैसे Compose के बाकी निर्देशों के साथ. साइज़ पर असर डालने वाले मॉडिफ़ायर के गलत प्लेसमेंट की वजह से, शेयर किए गए एलिमेंट मैचिंग के दौरान अनचाहे विज़ुअल जंप आ सकते हैं.

उदाहरण के लिए, अगर दो शेयर किए गए एलिमेंट पर पैडिंग मॉडिफ़ायर को किसी अलग जगह पर रखा जाता है, तो ऐनिमेशन में एक विज़ुअल अंतर होता है.

var selectFirst by remember { mutableStateOf(true) }
val key = remember { Any() }
SharedTransitionLayout(
    Modifier
        .fillMaxSize()
        .padding(10.dp)
        .clickable {
            selectFirst = !selectFirst
        }
) {
    AnimatedContent(targetState = selectFirst, label = "AnimatedContent") { targetState ->
        if (targetState) {
            Box(
                Modifier
                    .padding(12.dp)
                    .sharedBounds(
                        rememberSharedContentState(key = key),
                        animatedVisibilityScope = this@AnimatedContent
                    )
                    .border(2.dp, Color.Red)
            ) {
                Text(
                    "Hello",
                    fontSize = 20.sp
                )
            }
        } else {
            Box(
                Modifier
                    .offset(180.dp, 180.dp)
                    .sharedBounds(
                        rememberSharedContentState(
                            key = key,
                        ),
                        animatedVisibilityScope = this@AnimatedContent
                    )
                    .border(2.dp, Color.Red)
                    // This padding is placed after sharedBounds, but it doesn't match the
                    // other shared elements modifier order, resulting in visual jumps
                    .padding(12.dp)

            ) {
                Text(
                    "Hello",
                    fontSize = 36.sp
                )
            }
        }
    }
}

मैच होने वाले बाउंड

बॉउंड मैच नहीं होने पर: देखें कि शेयर किए गए एलिमेंट का ऐनिमेशन थोड़ा अलग कैसे दिखता है, क्योंकि उसे गलत बॉउंड के हिसाब से साइज़ करना पड़ता है

शेयर किए गए एलिमेंट मॉडिफ़ायर से पहले इस्तेमाल किए गए मॉडिफ़ायर से, शेयर किए गए एलिमेंट मॉडिफ़ायर में कंस्ट्रेंट की सुविधा मिलती है. इसका इस्तेमाल शुरुआती और टारगेट बाउंड पाने के लिए किया जाता है. इसके बाद, बाउंड ऐनिमेशन का भी इस्तेमाल किया जाता है.

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

हालांकि, अगर ऐनिमेशन के लिए resizeMode = ScaleToBounds() या किसी कंपोज़ेबल में Modifier.skipToLookaheadSize() का इस्तेमाल किया जाता है, तो यह इसका अपवाद है. इस मामले में, Compose टारगेट की सीमाओं का इस्तेमाल करके चाइल्ड लेआउट करता है. साथ ही, लेआउट का साइज़ बदलने के बजाय, ऐनिमेशन करने के लिए स्केल फ़ैक्टर का इस्तेमाल करता है.

यूनीक बटन

शेयर किए गए कॉम्प्लेक्स एलिमेंट के साथ काम करते समय, ऐसी कुंजी बनाना अच्छा तरीका है जो स्ट्रिंग न हो. ऐसा इसलिए, क्योंकि स्ट्रिंग के मैच होने में गड़बड़ी हो सकती है. मैच होने के लिए, हर कुंजी यूनीक होनी चाहिए. उदाहरण के लिए, Jetsnack में ये एलिमेंट शेयर किए जाते हैं:

सातवीं इमेज. यूज़र इंटरफ़ेस (यूआई) के हर हिस्से के लिए, एनोटेशन के साथ Jetspark दिखा रही इमेज.

शेयर किए गए एलिमेंट टाइप को दिखाने के लिए, एक एनमम बनाएं. इस उदाहरण में पूरा स्नैक कार्ड, होम स्क्रीन पर कई अलग-अलग जगहों से भी दिख सकता है. जैसे, "लोकप्रिय" और "सुझाया गया" सेक्शन में. ऐसी कुंजी बनाई जा सकती है जिसमें snackId, origin ("लोकप्रिय" / "सुझाया गया") और शेयर किए जाने वाले शेयर किए गए एलिमेंट का type हो:

data class SnackSharedElementKey(
    val snackId: Long,
    val origin: String,
    val type: SnackSharedElementType
)

enum class SnackSharedElementType {
    Bounds,
    Image,
    Title,
    Tagline,
    Background
}

@Composable
fun SharedElementUniqueKey() {
    // ...
            Box(
                modifier = Modifier
                    .sharedElement(
                        rememberSharedContentState(
                            key = SnackSharedElementKey(
                                snackId = 1,
                                origin = "latest",
                                type = SnackSharedElementType.Image
                            )
                        ),
                        animatedVisibilityScope = this@AnimatedVisibility
                    )
            )
            // ...
}

कुंजियों के लिए डेटा क्लास का सुझाव दिया जाता है, क्योंकि hashCode() और isEquals() को लागू किया जाता है.

शेयर किए गए एलिमेंट को दिखाने की सुविधा को मैन्युअल तरीके से मैनेज करें

अगर AnimatedVisibility या AnimatedContent का इस्तेमाल नहीं किया जा रहा है, तो शेयर किए गए एलिमेंट के दिखने की सेटिंग को खुद मैनेज किया जा सकता है. Modifier.sharedElementWithCallerManagedVisibility() का इस्तेमाल करें और अपनी शर्त दें, जिससे यह तय होता है कि आइटम कब दिखना चाहिए या नहीं:

var selectFirst by remember { mutableStateOf(true) }
val key = remember { Any() }
SharedTransitionLayout(
    Modifier
        .fillMaxSize()
        .padding(10.dp)
        .clickable {
            selectFirst = !selectFirst
        }
) {
    Box(
        Modifier
            .sharedElementWithCallerManagedVisibility(
                rememberSharedContentState(key = key),
                !selectFirst
            )
            .background(Color.Red)
            .size(100.dp)
    ) {
        Text(if (!selectFirst) "false" else "true", color = Color.White)
    }
    Box(
        Modifier
            .offset(180.dp, 180.dp)
            .sharedElementWithCallerManagedVisibility(
                rememberSharedContentState(
                    key = key,
                ),
                selectFirst
            )
            .alpha(0.5f)
            .background(Color.Blue)
            .size(180.dp)
    ) {
        Text(if (selectFirst) "false" else "true", color = Color.White)
    }
}

मौजूदा सीमाएं

इन एपीआई की कुछ सीमाएं हैं. सबसे ज़्यादा ध्यान देने वाली बातें:

  • व्यू और कॉम्पोज़ के बीच इंटरऑपरेबिलिटी काम नहीं करती. इसमें AndroidView को रैप करने वाला कोई भी कॉम्पोज़ेबल शामिल है, जैसे कि Dialog.
  • इनके लिए, अपने-आप ऐनिमेशन बनने की सुविधा उपलब्ध नहीं है:
    • शेयर की गई इमेज के कॉम्पोज़ेबल:
      • ContentScale डिफ़ॉल्ट रूप से ऐनिमेशन नहीं करता. यह सेट एंड में बदल जाता है ContentScale.
    • आकार काटना - आकारों के बीच अपने-आप एनिमेशन होने की सुविधा, पहले से मौजूद नहीं है. उदाहरण के लिए, आइटम के ट्रांज़िशन के तौर पर, स्क्वेयर से सर्कल में एनिमेट करना.
    • जिन मामलों में यह सुविधा काम नहीं करती उनके लिए, sharedElement() के बजाय Modifier.sharedBounds() का इस्तेमाल करें. साथ ही, आइटम में Modifier.animateEnterExit() जोड़ें.