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

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

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

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

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

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

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

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

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

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

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

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

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

  1. शेयर किए गए एलिमेंट को दो लेआउट के बीच ऐनिमेट करने के लिए, AnimatedContent कॉम्पोज़ेबल को SharedTransitionLayout से घेरें. 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 टारगेट की सीमाओं का इस्तेमाल करके चाइल्ड लेआउट करता है. साथ ही, लेआउट का साइज़ बदलने के बजाय, ऐनिमेशन करने के लिए स्केल फ़ैक्टर का इस्तेमाल करता है.

यूनीक बटन

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

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

शेयर किए गए एलिमेंट टाइप को दिखाने के लिए, एक enum बनाया जा सकता है. इस उदाहरण में, स्नैक कार्ड का पूरा हिस्सा होम स्क्रीन पर कई जगहों पर दिख सकता है. उदाहरण के लिए, "लोकप्रिय" और "सुझाए गए" सेक्शन में. शेयर किए जाने वाले एलिमेंट के लिए, 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() जोड़ें.