From 8fcf6147d996d82ea13b7ab054dcf2c6c0ea4861 Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Mon, 1 Dec 2025 12:00:59 +0000 Subject: [PATCH 1/2] Add snippet to create dynamic shared elements --- .../CustomizeSharedElementsSnippets.kt | 93 ++++++++++++++++--- .../sharedelement/SharedBoundsSnippets.kt | 4 +- .../SharedElementCommonUseCaseSnippets.kt | 2 +- gradle/libs.versions.toml | 4 +- 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt index 079c68347..905d8fbd4 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt @@ -35,16 +35,19 @@ import androidx.compose.animation.core.SeekableTransitionState import androidx.compose.animation.core.keyframes import androidx.compose.animation.core.rememberTransition import androidx.compose.animation.core.tween +import androidx.compose.animation.core.updateTransition import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -62,6 +65,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Create import androidx.compose.material.icons.outlined.Favorite import androidx.compose.material.icons.outlined.Share +import androidx.compose.material3.Checkbox import androidx.compose.material3.Icon import androidx.compose.material3.Slider import androidx.compose.material3.Surface @@ -69,6 +73,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -83,6 +88,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.glance.currentState import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -272,10 +278,10 @@ private fun DetailsContent( // [END android_compose_shared_element_text_bounds_transform] Text( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet lobortis velit. " + - "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + - " Curabitur sagittis, lectus posuere imperdiet facilisis, nibh massa " + - "molestie est, quis dapibus orci ligula non magna. Pellentesque rhoncus " + - "hendrerit massa quis ultricies. Curabitur congue ullamcorper leo, at maximus", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + + " Curabitur sagittis, lectus posuere imperdiet facilisis, nibh massa " + + "molestie est, quis dapibus orci ligula non magna. Pellentesque rhoncus " + + "hendrerit massa quis ultricies. Curabitur congue ullamcorper leo, at maximus", modifier = Modifier.skipToLookaheadSize() ) } @@ -332,7 +338,7 @@ private fun SharedElement_Clipping() { rememberSharedContentState(key = "title"), animatedVisibilityScope = this@AnimatedContent, - ) + ) ) } } else { @@ -370,10 +376,10 @@ private fun SharedElement_Clipping() { ) Text( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet lobortis velit. " + - "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + - " Curabitur sagittis, lectus posuere imperdiet facilisis, nibh massa " + - "molestie est, quis dapibus orci ligula non magna. Pellentesque rhoncus " + - "hendrerit massa quis ultricies. Curabitur congue ullamcorper leo, at maximus" + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + + " Curabitur sagittis, lectus posuere imperdiet facilisis, nibh massa " + + "molestie est, quis dapibus orci ligula non magna. Pellentesque rhoncus " + + "hendrerit massa quis ultricies. Curabitur congue ullamcorper leo, at maximus" ) } } @@ -574,7 +580,6 @@ fun PlaceholderSizeAnimated_Demo() { .sharedBounds( rememberSharedContentState(key = "image-${snack.name}"), animatedVisibilityScope = this@composable, - placeHolderSize = SharedTransitionScope.PlaceHolderSize.animatedSize ) .clickable { navController.navigate("details/$index") @@ -624,7 +629,6 @@ fun PlaceholderSizeAnimated_Demo() { .sharedBounds( rememberSharedContentState(key = "image-${snack.name}"), animatedVisibilityScope = this@composable, - placeHolderSize = SharedTransitionScope.PlaceHolderSize.animatedSize ) .clip(RoundedCornerShape(8.dp)) .fillMaxWidth() @@ -730,3 +734,70 @@ fun CustomPredictiveBackHandle() { // [END android_compose_shared_element_custom_seeking] } + +@Composable +@Preview +fun DynamicSharedElements() { + var currentState by remember { + mutableStateOf("A") + } + // [START android_compose_shared_element_dynamic_enable_disable] + SharedTransitionLayout { + val transition = updateTransition(currentState) + transition.AnimatedContent { targetState -> + // 1. Define your condition & create the configuration + fun animationConfig() : SharedTransitionScope.SharedContentConfig { + return object : SharedTransitionScope.SharedContentConfig { + override val SharedTransitionScope.SharedContentState.isEnabled: Boolean + // For this example, we only enable the transition in one direction + // from A -> B and not the other way around. + get() = + transition.currentState == "A" && transition.targetState == "B" + } + } + when (targetState) { + "A" -> Box( + modifier = Modifier + .sharedElement( + rememberSharedContentState( + key = "shared_box", + config = animationConfig() + ), + animatedVisibilityScope = this + ) + // [START_EXCLUDE] + .size(100.dp) + .background(Color.Red) + .clickable { + currentState = "B" + } + // [END_EXCLUDE] + ) { + // Your content + } + "B" -> { + Box( + modifier = Modifier + .sharedElement( + rememberSharedContentState( + key = "shared_box", + config = animationConfig() + ), + animatedVisibilityScope = this + ) + // [START_EXCLUDE] + .size(200.dp) + .background(Color.Blue) + .clickable { + currentState = "A" + } + // [END_EXCLUDE] + ) { + // Your content + } + } + } + } + } + // [END android_compose_shared_element_dynamic_enable_disable] +} diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedBoundsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedBoundsSnippets.kt index 3878fa6ad..abf5470cf 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedBoundsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedBoundsSnippets.kt @@ -102,7 +102,7 @@ private fun MainContent( animatedVisibilityScope = animatedVisibilityScope, enter = fadeIn(), exit = fadeOut(), - resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds() + resizeMode = SharedTransitionScope.ResizeMode.scaleToBounds() ) // [START_EXCLUDE] .border(1.dp, Color.Gray.copy(alpha = 0.5f), RoundedCornerShape(8.dp)) @@ -154,7 +154,7 @@ private fun DetailsContent( animatedVisibilityScope = animatedVisibilityScope, enter = fadeIn(), exit = fadeOut(), - resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds() + resizeMode = SharedTransitionScope.ResizeMode.scaleToBounds() ) // [START_EXCLUDE] .border(1.dp, Color.Gray.copy(alpha = 0.5f), RoundedCornerShape(8.dp)) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedElementCommonUseCaseSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedElementCommonUseCaseSnippets.kt index 944122d1d..bd0ccc716 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedElementCommonUseCaseSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/SharedElementCommonUseCaseSnippets.kt @@ -92,7 +92,7 @@ private fun SharedElementTypicalUseText() { animatedVisibilityScope = this, enter = fadeIn(), exit = fadeOut(), - resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds() + resizeMode = SharedTransitionScope.ResizeMode.scaleToBounds() ) ) // [END android_compose_shared_element_text_tip] diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40c26140b..4280e0a0b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ android-googleid = "1.1.1" androidGradlePlugin = "8.13.0" androidx-activity-compose = "1.11.0" androidx-appcompat = "1.7.0" -androidx-compose-bom = "2025.10.01" +androidx-compose-bom = "2025.11.01" androidx-compose-ui-test = "1.7.0-alpha08" androidx-compose-ui-test-junit4-accessibility = "1.10.0-beta01" androidx-constraintlayout = "2.2.1" @@ -103,7 +103,7 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } androidx-compose-animation-graphics = { module = "androidx.compose.animation:animation-graphics", version.ref = "compose-latest" } -androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidx-compose-bom" } +androidx-compose-bom = { module = "androidx.compose:compose-bom-alpha", version.ref = "androidx-compose-bom" } androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose-latest" } androidx-compose-foundation-layout = { module = "androidx.compose.foundation:foundation-layout", version.ref = "compose-latest" } androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "compose-latest" } From af40fbaf9656f40926dd01d95394743daa7de2cd Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Mon, 1 Dec 2025 12:08:10 +0000 Subject: [PATCH 2/2] Change comments to Config that depends on state changing --- .../animations/sharedelement/CustomizeSharedElementsSnippets.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt index 905d8fbd4..98b2c5b6b 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/animations/sharedelement/CustomizeSharedElementsSnippets.kt @@ -745,7 +745,7 @@ fun DynamicSharedElements() { SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> - // 1. Define your condition & create the configuration + // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean