You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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__

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:14:50