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

Compose中如何为可独立缩放的两个Surface添加统一elevation效果

解决Jetpack Compose中多Surface统一阴影的方案

针对你遇到的两个Surface需要保持独立缩放动画、同时实现统一阴影的问题,有两种实用方案:

方案一:父容器承载统一阴影(最简单)

用一个父布局(比如Box或Column)添加整体阴影,内部两个Surface去掉自身的elevation,并通过形状设置让它们视觉上无缝贴合。这样父容器的阴影是完整的,内部Surface可以各自执行缩放动画,不会破坏整体阴影效果。

示例代码:

@Composable
fun UnifiedShadowSurfaces() {
    val isTopScaled by remember { mutableStateOf(false) }
    val isBottomScaled by remember { mutableStateOf(false) }
    val topSurfaceHeight = 100.dp
    val cornerRadius = 16.dp

    Box(
        modifier = Modifier
            .padding(20.dp)
            .shadow(
                elevation = 8.dp,
                shape = RoundedCornerShape(cornerRadius)
            )
    ) {
        Column {
            // 顶部Surface:仅水平缩放,顶部圆角保留,底部圆角设为0
            Surface(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(topSurfaceHeight)
                    .scale(scaleX = if (isTopScaled) 0.9f else 1f)
                    .align(Alignment.CenterHorizontally),
                elevation = 0.dp,
                shape = RoundedCornerShape(
                    topStart = cornerRadius,
                    topEnd = cornerRadius,
                    bottomStart = 0.dp,
                    bottomEnd = 0.dp
                )
            ) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Text("顶部区域")
                    Button(onClick = { isTopScaled = !isTopScaled }) {
                        Text("水平缩放")
                    }
                }
            }

            // 底部Surface:仅垂直缩放,底部圆角保留,顶部圆角设为0
            Surface(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
                    .scale(scaleY = if (isBottomScaled) 0.9f else 1f)
                    .align(Alignment.CenterHorizontally),
                elevation = 0.dp,
                shape = RoundedCornerShape(
                    topStart = 0.dp,
                    topEnd = 0.dp,
                    bottomStart = cornerRadius,
                    bottomEnd = cornerRadius
                )
            ) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Text("底部区域")
                    Button(onClick = { isBottomScaled = !isBottomScaled }) {
                        Text("垂直缩放")
                    }
                }
            }
        }
    }
}

方案二:自定义绘制组合阴影(更灵活)

如果两个Surface的布局比较复杂(非简单上下堆叠),可以通过drawBehind手动绘制两个Surface组合后的整体阴影路径,完全自定义阴影的形状和范围。

示例代码:

@Composable
fun CustomUnifiedShadowSurfaces() {
    val isTopScaled by remember { mutableStateOf(false) }
    val isBottomScaled by remember { mutableStateOf(false) }
    val topSurfaceHeight = 100.dp
    val cornerRadius = 16.dp

    Box(
        modifier = Modifier
            .padding(20.dp)
            .drawBehind {
                // 计算两个Surface的位置和形状,组合成统一路径
                val topRect = Rect(
                    left = 0f,
                    top = 0f,
                    right = size.width,
                    bottom = topSurfaceHeight.toPx()
                )
                val bottomRect = Rect(
                    left = 0f,
                    top = topSurfaceHeight.toPx(),
                    right = size.width,
                    bottom = size.height
                )

                val combinedPath = Path().apply {
                    // 添加顶部Surface的圆角矩形路径
                    addRoundRect(
                        RoundRect(
                            rect = topRect,
                            topLeft = CornerRadius(cornerRadius.toPx()),
                            topRight = CornerRadius(cornerRadius.toPx()),
                            bottomLeft = CornerRadius(0f),
                            bottomRight = CornerRadius(0f)
                        )
                    )
                    // 添加底部Surface的圆角矩形路径
                    addRoundRect(
                        RoundRect(
                            rect = bottomRect,
                            topLeft = CornerRadius(0f),
                            topRight = CornerRadius(0f),
                            bottomLeft = CornerRadius(cornerRadius.toPx()),
                            bottomRight = CornerRadius(cornerRadius.toPx())
                        )
                    )
                }

                // 绘制统一阴影
                drawShadow(
                    path = combinedPath,
                    elevation = 8.dp.toPx(),
                    ambientColor = Color.Black.copy(alpha = 0.12f),
                    spotColor = Color.Black.copy(alpha = 0.2f)
                )
            }
    ) {
        // 内部两个Surface,同样去掉elevation,设置对应形状和缩放动画
        Surface(
            modifier = Modifier
                .fillMaxWidth()
                .height(topSurfaceHeight)
                .scale(scaleX = if (isTopScaled) 0.9f else 1f)
                .align(Alignment.CenterHorizontally),
            elevation = 0.dp,
            shape = RoundedCornerShape(
                topStart = cornerRadius,
                topEnd = cornerRadius,
                bottomStart = 0.dp,
                bottomEnd = 0.dp
            )
        ) { /* 顶部内容 */ }

        Surface(
            modifier = Modifier
                .fillMaxWidth()
                .height(100.dp)
                .scale(scaleY = if (isBottomScaled) 0.9f else 1f)
                .align(Alignment.CenterHorizontally),
            elevation = 0.dp,
            shape = RoundedCornerShape(
                topStart = 0.dp,
                topEnd = 0.dp,
                bottomStart = cornerRadius,
                bottomEnd = cornerRadius
            )
        ) { /* 底部内容 */ }
    }
}

关键注意点

  • 两个Surface必须设置对应的圆角形状,确保边缘无缝贴合,避免出现视觉缝隙。
  • 内部Surface的elevation必须设为0.dp,防止自身产生阴影破坏整体效果。
  • 缩放动画仅作用于单个Surface,父容器的阴影保持稳定,实现整体视觉统一。

内容的提问来源于stack exchange,提问作者Martim Gouveia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:50:22