通过DeepLink打开应用时SharedTransition API引发崩溃问题
DeepLink打开Compose应用崩溃:Uninitialized LayoutCoordinates问题解决
问题现象
通过通知或Widget的DeepLink打开应用时,应用直接崩溃,崩溃堆栈核心错误:
java.lang.IllegalArgumentException: Error: Uninitialized LayoutCoordinates. Please make sure when using the SharedTransitionScope composable function, the modifier passed to the child content is being used, or use SharedTransitionLayout instead.
崩溃原因
- 共享元素上下文缺失:直接通过DeepLink进入
DefinitionScreen时,HomeScreen并未加载,导致SharedTransitionScope依赖的布局上下文未初始化。 - 无效的Scope传递:代码中传递的
AnimatedContentScope仅在导航动画触发时有效,DeepLink直接跳转时没有触发导航动画,该Scope处于无效状态,进而导致共享元素的布局坐标无法获取。
修复方案
核心修改点
- 移除对
AnimatedContentScope的直接传递,改用SharedTransitionScope自身上下文管理共享元素状态 - 通过路由参数标记是否来自共享跳转,仅在合法场景下启用共享元素动画
- 确保
SharedTransitionLayout的布局上下文正确绑定到所有共享元素
完整代码修改
1. 导航宿主与路由配置
@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun EnglishDictionaryNavHost(modifier: Modifier = Modifier) { SharedTransitionLayout(modifier = modifier) { val navController = rememberNavController() NavHost( modifier = modifier, navController = navController, startDestination = Home, ) { definitionScreen( sharedTransitionScope = this@SharedTransitionLayout, onNavigateBack = { navController.popBackStack() } ) homeScreen( sharedTransitionScope = this@SharedTransitionLayout, onNavigateToDefinition = { word, isWotd -> navController.navigate(DefinitionRoute(word, isWotd)) } ) } } } @Serializable data object Home @Serializable data class DefinitionRoute(val word: String, val isWotd: Boolean = false)
2. HomeScreen与WordOfTheDay组件
fun NavGraphBuilder.homeScreen( sharedTransitionScope: SharedTransitionScope, onNavigateToDefinition: (String, Boolean) -> Unit ) { composable<Home> { HomeScreen( sharedTransitionScope = sharedTransitionScope, onNavigateToDefinition = onNavigateToDefinition ) } } @OptIn(ExperimentalMaterial3Api::class) @Composable private fun HomeScreen( sharedTransitionScope: SharedTransitionScope, onNavigateToDefinition: (String, Boolean) -> Unit ) { Scaffold() { paddingValues -> LazyColumn(contentPadding = paddingValues) { item { WordOfTheDay( sharedTransitionScope = sharedTransitionScope, onNavigate = onNavigateToDefinition ) } } } } @Composable private fun WordOfTheDay( sharedTransitionScope: SharedTransitionScope, onNavigate: (String, Boolean) -> Unit ) { val word = wordOfTheDay.word Card( modifier = Modifier .fillMaxWidth() .padding(16.dp) .clickable { onNavigate(word, true) } ) { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { with(sharedTransitionScope) { Text( text = word, style = MaterialTheme.typography.headlineLarge, modifier = Modifier.sharedElement( rememberSharedContentState(key = word) ) ) } } } }
3. DefinitionScreen与TopAppBar组件
fun NavGraphBuilder.definitionScreen( sharedTransitionScope: SharedTransitionScope, onNavigateBack: () -> Unit ) { composable<DefinitionRoute>(deepLinks = listOf(navDeepLink { uriPattern = "app://com.ayitinya.englishdictionary/{word}" })) { backStackEntry -> val route = backStackEntry.toRoute<DefinitionRoute>() DefinitionScreen( sharedTransitionScope = sharedTransitionScope, word = route.word, isWotd = route.isWotd, onNavigateBack = onNavigateBack ) } } @OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) @Composable private fun DefinitionScreen( sharedTransitionScope: SharedTransitionScope, word: String, isWotd: Boolean, onNavigateBack: () -> Unit ) { val lazyListState = rememberLazyListState() Scaffold( topBar = { TopAppBar( sharedTransitionScope = sharedTransitionScope, word = word, enableSharedTransition = isWotd, onNavigateBack = onNavigateBack ) } // 原有页面内容保留 ) } @OptIn(ExperimentalMaterial3Api::class, ExperimentalSharedTransitionApi::class) @Composable private fun TopAppBar( sharedTransitionScope: SharedTransitionScope, word: String, enableSharedTransition: Boolean, onNavigateBack: () -> Unit ) { LargeTopAppBar( title = { if (enableSharedTransition) { with(sharedTransitionScope) { Text( text = word, modifier = Modifier .weight(4f) .sharedElement( rememberSharedContentState(key = word) ) ) } } else { Text( text = word, modifier = Modifier.weight(4f) ) } }, navigationIcon = { IconButton(onClick = onNavigateBack) { Icon(Icons.Default.ArrowBack, contentDescription = "返回") } } ) }
关键修复说明
- 移除
AnimatedContentScope参数:该Scope仅在导航动画流程中有效,DeepLink直接进入时无有效上下文,会导致布局坐标初始化失败。 - 增加
isWotd路由参数:标记是否来自HomeScreen的共享跳转,仅在该场景下启用共享元素动画,DeepLink直接进入时使用普通Text组件,避免触发未初始化的共享过渡。 - 共享元素状态绑定:通过
SharedTransitionScope自身的rememberSharedContentState创建状态,确保布局上下文正确关联。
内容的提问来源于stack exchange,提问作者ayitinya
相关产品推荐
相关产品推荐

