Jetpack Compose中按钮显隐时宽度平滑过渡的实现问题
解决Jetpack Compose中按钮宽度平滑过渡的问题
你的问题核心在于fillMaxWidth()会让Button1的宽度瞬间响应布局约束变化,而animateContentSize()仅适用于组件自身内容变化(比如文本长度改变)的场景,无法处理布局约束变化带来的尺寸跳变。下面提供两种可行的解决方案:
方案一:手动计算并动画化Button1的宽度
通过记录Button2的实际宽度,结合动画API动态调整Button1的宽度,实现平滑过渡:
var show by remember { mutableStateOf(false) } var button2Width by remember { mutableStateOf(0.dp) } BoxWithConstraints(modifier = Modifier.fillMaxWidth()) { val rowMaxWidth = maxWidth // 为Button1的宽度创建过渡动画 val button1TargetWidth by animateDpAsState( targetValue = if (show) rowMaxWidth - button2Width - 8.dp else rowMaxWidth, animationSpec = tween(300) ) Column( modifier = Modifier.fillMaxSize().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Button(onClick = { show = !show }) { Text("Click") } Spacer(modifier = Modifier.padding(32.dp)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { AnimatedVisibility( visible = show, exit = fadeOut() + slideOutHorizontally(), enter = fadeIn() + slideInHorizontally() ) { OutlinedButton( onClick = {}, modifier = Modifier.onSizeChanged { size -> // 记录Button2的实际宽度 button2Width = size.width.toDp() } ) { Text("Button 2") } } Button( modifier = Modifier.width(button1TargetWidth), onClick = {} ) { Text("Button 1") } } } }
关键逻辑:
- 用
onSizeChanged监听Button2的尺寸变化,记录其实际宽度 - 用
BoxWithConstraints获取Row的最大可用宽度,确保Button1的宽度计算准确 - 通过
animateDpAsState绑定show状态,为Button1的宽度创建平滑过渡动画
方案二:使用AnimatedContent自动处理布局动画
利用AnimatedContent封装Row的内容,让Compose自动处理布局变化的过渡动画,代码更简洁:
var show by remember { mutableStateOf(false) } Column( modifier = Modifier.fillMaxSize().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Button(onClick = { show = !show }) { Text("Click") } Spacer(modifier = Modifier.padding(32.dp)) AnimatedContent( targetState = show, transitionSpec = { // 同步进入/退出动画时长,开启尺寸变换动画 fadeIn() + slideInHorizontally() with fadeOut() + slideOutHorizontally() using SizeTransform(clip = false) } ) { isShow -> Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { if (isShow) { OutlinedButton(onClick = {}) { Text("Button 2") } } Button( modifier = Modifier.fillMaxWidth(), onClick = {} ) { Text("Button 1") } } } }
关键逻辑:
AnimatedContent会在targetState变化时,对新旧布局的尺寸差异应用过渡动画SizeTransform(clip = false)确保动画过程中组件不会被裁剪,保证视觉连续性
两种方案都能实现你需要的效果:方案一适合需要精确控制动画参数的场景,方案二更适合快速实现布局过渡的需求。
内容的提问来源于stack exchange,提问作者Danfb__
相关产品推荐
相关产品推荐

