如何使用Jetpack Compose实现搜索框场景过渡动画
在Jetpack Compose中实现搜索框跨页面缩小重叠过渡动画
我有两个Compose页面:
- 第一个页面顶部是静态宽搜索框,点击后跳转至第二个实际搜索界面
- 第二个页面的搜索框样式相近,但宽度更小
期望实现的效果:跳转时第一个页面的搜索框快速缩小,与第二个页面的搜索框平滑重叠。
在传统View体系中,我会用以下方式实现:
val bundle = ActivityOptionsCompat .makeSceneTransitionAnimation(requireActivity(), toolbar, "llSearch").toBundle()
现在我用navController.navigateTo(page2)进行页面跳转,请问怎么用Jetpack Compose实现这个搜索框的过渡动画?
实现方案
1. 配置NavHost启用共享元素过渡
首先要确保NavHost支持共享元素过渡,通过rememberSharedTransitionScope关联导航控制器,并配置过渡动画参数:
@Composable fun MainNavHost(navController: NavHostController) { rememberSharedTransitionScope() NavHost( navController = navController, startDestination = "page1", // 基础页面过渡(可选,用于非共享元素部分) enterTransition = { fadeIn(tween(200)) }, exitTransition = { fadeOut(tween(200)) }, // 共享元素进入/退出动画配置 sharedElementsEnterTransition = { scaleIn( initialScale = 1f, animationSpec = tween(durationMillis = 300) ) + fadeIn(tween(300)) }, sharedElementsExitTransition = { scaleOut( targetScale = 0.7f, animationSpec = tween(durationMillis = 300) ) + fadeOut(tween(300)) } ) { composable("page1") { Page1(navController) } composable("page2") { Page2() } } }
2. 为两个页面的搜索框标记共享元素
使用相同的共享元素Key,用SharedTransitionLayout包裹搜索框组件,让Compose跟踪元素的尺寸和位置变化:
页面1(宽搜索框)
@Composable fun Page1(navController: NavHostController) { val searchBarSharedState = rememberSharedContentState(key = "search_bar") Column(modifier = Modifier.fillMaxSize()) { SharedTransitionLayout(sharedContentState = searchBarSharedState) { TextField( value = "", onValueChange = {}, modifier = Modifier .fillMaxWidth() .height(56.dp) .sharedContent(key = "search_bar"), placeholder = { Text("搜索") } ) } Button( modifier = Modifier.padding(top = 20.dp), onClick = { navController.navigate("page2") } ) { Text("跳转到搜索页") } } }
页面2(窄搜索框)
@Composable fun Page2() { val searchBarSharedState = rememberSharedContentState(key = "search_bar") Column(modifier = Modifier.fillMaxSize()) { SharedTransitionLayout(sharedContentState = searchBarSharedState) { TextField( value = "", onValueChange = {}, modifier = Modifier .width(300.dp) .height(56.dp) .align(Alignment.CenterHorizontally) .sharedContent(key = "search_bar"), placeholder = { Text("搜索") } ) } } }
3. 自定义动画细节(可选)
如果需要更贴合需求的"快速缩小"效果,可以调整动画的时长、曲线等参数:
// 自定义快速缩小的进入动画 val customEnterAnim = remember { sharedElementEnterTransition { scaleIn( initialScale = 1f, targetScale = 0.7f, // 缩短时长实现快速效果 animationSpec = tween(durationMillis = 200, easing = FastOutLinearInEasing) ) + fadeIn(tween(200)) } } // 对应退出动画 val customExitAnim = remember { sharedElementExitTransition { scaleOut( initialScale = 1f, targetScale = 0.7f, animationSpec = tween(durationMillis = 200, easing = FastOutLinearInEasing) ) + fadeOut(tween(200)) } }
将上述动画替换到NavHost的sharedElementsEnterTransition和sharedElementsExitTransition参数中即可。
核心注意点
- 两个页面的共享元素必须使用完全相同的Key(示例中为
"search_bar"),这是Compose识别共享元素的唯一标识 SharedTransitionLayout负责绑定共享元素的状态,必须包裹目标组件- 动画参数可以根据需求灵活调整,
tween的durationMillis控制动画速度,easing控制动画曲线
内容的提问来源于stack exchange,提问作者有朋自远方来
相关产品推荐
相关产品推荐

