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
相关产品推荐
相关产品推荐

