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

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

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

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

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

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

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

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

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

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

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

यूनीक बटन

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

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

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