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

Jetpack Compose中如何实现绘制内容与文本并排(无需Padding)

问题描述

我在Column组件中使用drawBehind API绘制竖线,希望文本能与该竖线并排显示。当前代码的实际效果是线条覆盖了文本;虽然给Column添加padding(start = 120.dp)可以实现预期的并排效果,但我想避免使用这种Padding方式,请问是否有其他可行的实现方案?

现有代码

@Preview(showBackground = true)
@Composable
fun ItemView() {
    val names = listOf("Captain" to "Vice Captain")
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        itemsIndexed(names) { index, item ->

            var titleCoordinates by remember { mutableStateOf<LayoutCoordinates?>(null) }
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .drawBehind {
                        val titleBounds = titleCoordinates?.boundsInParent()
                        if (titleBounds != null) {
                            val offset = Offset(x = center.x / 2, y = titleBounds.top)
                            drawLine(
                                color = Color.Black,
                                start = offset,
                                end = offset.copy(y = size.height),
                                strokeWidth = 2.dp.toPx(),
                            )
                        }
                    }
            ) {
                Box(
                    Modifier
                        .padding(top = 24.dp)
                        .onGloballyPositioned { titleCoordinates = it }
                ) {
                    Text(text = item.first, color = Color.Red)
                }
                Text(text = item.second, color = Color.Blue)
            }
        }
    }
}

效果说明

  • 实际效果:绘制的竖线直接覆盖在文本上方,导致文本被遮挡
  • 预期效果:竖线与文本并排显示,文本不被遮挡

解决方案

方案1:用Row分离线条与文本区域

将线条绘制和文本布局拆分为Row的两个子组件,彻底避免层级覆盖问题:

@Preview(showBackground = true)
@Composable
fun ItemView() {
    val names = listOf("Captain" to "Vice Captain")
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        itemsIndexed(names) { index, item ->
            Row(Modifier.fillMaxWidth()) {
                // 竖线绘制区域
                Box(
                    modifier = Modifier
                        .width(120.dp)
                        .fillMaxHeight()
                        .drawBehind {
                            val lineStartY = 24.dp.toPx()
                            drawLine(
                                color = Color.Black,
                                start = Offset(size.width, lineStartY),
                                end = Offset(size.width, size.height),
                                strokeWidth = 2.dp.toPx(),
                            )
                        }
                )
                // 文本区域
                Column(Modifier.fillMaxWidth()) {
                    Text(
                        text = item.first,
                        color = Color.Red,
                        modifier = Modifier.padding(top = 24.dp)
                    )
                    Text(text = item.second, color = Color.Blue)
                }
            }
        }
    }
}

方案2:给文本单独设置偏移,配合drawBehind

不给Column整体加padding,而是直接给每个Text组件设置start方向的padding,确保文本避开线条位置:

@Preview(showBackground = true)
@Composable
fun ItemView() {
    val names = listOf("Captain" to "Vice Captain")
    val lineOffset = 120.dp
    val textOffset = lineOffset + 10.dp // 线条与文本留间隙

    LazyColumn(modifier = Modifier.fillMaxSize()) {
        itemsIndexed(names) { index, item ->
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .drawBehind {
                        val lineX = lineOffset.toPx()
                        val lineStartY = 24.dp.toPx()
                        drawLine(
                            color = Color.Black,
                            start = Offset(lineX, lineStartY),
                            end = Offset(lineX, size.height),
                            strokeWidth = 2.dp.toPx(),
                        )
                    }
            ) {
                Text(
                    text = item.first,
                    color = Color.Red,
                    modifier = Modifier.padding(top = 24.dp, start = textOffset)
                )
                Text(
                    text = item.second,
                    color = Color.Blue,
                    modifier = Modifier.padding(start = textOffset)
                )
            }
        }
    }
}

方案3:自定义Layout实现动态位置

如果需要根据文本宽度动态调整线条位置,可通过自定义Layout精确控制元素位置:

@Preview(showBackground = true)
@Composable
fun ItemView() {
    val names = listOf("Captain" to "Vice Captain")
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        itemsIndexed(names) { index, item ->
            CustomLineTextLayout(
                title = item.first,
                subtitle = item.second,
                lineColor = Color.Black,
                lineWidth = 2.dp,
                gapBetweenLineAndText = 10.dp
            )
        }
    }
}

@Composable
fun CustomLineTextLayout(
    title: String,
    subtitle: String,
    lineColor: Color,
    lineWidth: Dp,
    gapBetweenLineAndText: Dp,
    modifier: Modifier = Modifier
) {
    Layout(
        content = {
            Text(text = title, color = Color.Red, modifier = Modifier.padding(top = 24.dp))
            Text(text = subtitle, color = Color.Blue)
        },
        modifier = modifier.fillMaxWidth()
    ) { measurables, constraints ->
        val titlePlaceable = measurables[0].measure(constraints)
        val subtitlePlaceable = measurables[1].measure(constraints)

        // 线条位置为标题宽度 + 间隙
        val lineX = titlePlaceable.width + gapBetweenLineAndText.toPx()
        val totalHeight = maxOf(
            titlePlaceable.height + 24.dp.toPx().toInt(),
            subtitlePlaceable.height
        )

        layout(constraints.maxWidth, totalHeight) {
            // 放置标题
            titlePlaceable.placeRelative(0, 24.dp.toPx().toInt())
            // 放置副标题
            subtitlePlaceable.placeRelative(0, titlePlaceable.height + 24.dp.toPx().toInt())

            // 绘制竖线
            drawIntoCanvas { canvas ->
                canvas.drawLine(
                    start = Offset(lineX, 24.dp.toPx()),
                    end = Offset(lineX, totalHeight.toFloat()),
                    paint = Paint().apply {
                        this.color = lineColor
                        strokeWidth = lineWidth.toPx()
                    }
                )
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:04:53