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

如何在Jetpack Compose中使用MotionLayout、MotionScene、ConstraintSet?

Jetpack Compose MotionLayout 折叠动画实现示例

你要实现的顶部折叠渐变动画用MotionLayout可以快速实现,以下是可直接运行的完整示例:

首先需要添加依赖:

// build.gradle(模块级) 依赖配置
dependencies {
    implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0"
}

核心实现代码:

@Composable
fun CollapsibleHeaderDemo() {
    // isCollapsed 可以由按钮点击或者列表滚动状态控制
    val isCollapsed = remember { mutableStateOf(false) }
    // 动画进度 0=完全展开 1=完全折叠
    val progress by animateFloatAsState(targetValue = if (isCollapsed.value) 1f else 0f, label = "collapseProgress")

    // 1. 定义展开状态的约束集
    val startConstraintSet = ConstraintSet {
        val headerBg = createRefFor("headerBg")
        val avatar = createRefFor("avatar")
        val username = createRefFor("username")
        val bio = createRefFor("bio")

        constrain(headerBg) {
            top.linkTo(parent.top)
            start.linkTo(parent.start)
            end.linkTo(parent.end)
            height = Dimension.value(200.dp)
        }
        constrain(avatar) {
            top.linkTo(headerBg.bottom, margin = (-40).dp)
            start.linkTo(parent.start, margin = 16.dp)
            width = Dimension.value(80.dp)
            height = Dimension.value(80.dp)
        }
        constrain(username) {
            top.linkTo(avatar.bottom, margin = 16.dp)
            start.linkTo(avatar.start)
        }
        constrain(bio) {
            top.linkTo(username.bottom, margin = 8.dp)
            start.linkTo(username.start)
            end.linkTo(parent.end, margin = 16.dp)
        }
    }

    // 2. 定义折叠状态的约束集
    val endConstraintSet = ConstraintSet {
        val headerBg = createRefFor("headerBg")
        val avatar = createRefFor("avatar")
        val username = createRefFor("username")
        val bio = createRefFor("bio")

        constrain(headerBg) {
            top.linkTo(parent.top)
            start.linkTo(parent.start)
            end.linkTo(parent.end)
            height = Dimension.value(56.dp)
        }
        constrain(avatar) {
            centerVerticallyTo(headerBg)
            start.linkTo(parent.start, margin = 16.dp)
            width = Dimension.value(32.dp)
            height = Dimension.value(32.dp)
        }
        constrain(username) {
            centerVerticallyTo(headerBg)
            start.linkTo(avatar.end, margin = 12.dp)
        }
        constrain(bio) {
            top.linkTo(headerBg.bottom)
            start.linkTo(username.start)
            end.linkTo(parent.end, margin = 16.dp)
            alpha = 0f // 折叠时隐藏简介
        }
    }

    // 3. 定义MotionScene配置过渡动画
    val motionScene = remember {
        MotionScene {
            defaultTransition(
                from = startConstraintSet,
                to = endConstraintSet
            ) {
                // 配置全局动画参数
                duration = 300
                ease = EaseInOutQuad
                // 单独指定简介透明度的动画曲线
                property("alpha", "bio") {
                    duration = 150
                }
            }
        }
    }

    // 4. MotionLayout承载内容
    MotionLayout(
        motionScene = motionScene,
        progress = progress,
        modifier = Modifier.fillMaxSize()
    ) {
        // 顶部背景栏
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Blue)
                .layoutId("headerBg")
        )
        // 头像
        Image(
            painter = painterResource(id = R.drawable.default_avatar),
            contentDescription = null,
            modifier = Modifier
                .clip(CircleShape)
                .layoutId("avatar")
        )
        // 用户名
        Text(
            text = "用户名",
            style = MaterialTheme.typography.titleLarge,
            color = Color.White,
            modifier = Modifier.layoutId("username")
        )
        // 个人简介
        Text(
            text = "这是个人简介内容,折叠时会隐藏",
            style = MaterialTheme.typography.bodyMedium,
            modifier = Modifier.layoutId("bio")
        )
    }
}

关键注意点

  • 所有子组件必须设置和ConstraintSet中对应的layoutId,否则约束不会生效
  • progress参数取值范围为0~1,和列表滚动进度绑定即可实现示例中跟随滚动逐步折叠的效果,不需要额外写补间动画
  • 可以单独对某个组件的某个属性配置专属的动画时长、插值器,实现更细腻的效果

学习参考

  • Android Studio内置的Compose样例库中包含多个MotionLayout的不同场景实现,新建项目时选择「Compose Samples」即可查看源码
  • ConstraintLayout Compose库的源码API注释对每个参数的说明非常详尽,可以直接在代码中跳转查看

内容的提问来源于stack exchange,提问作者Tiberiu Paduraru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:06:06