在 AnnotatedString 中的文本之间添加小的 padding/margin

3
每当我使用buildAnnotatedString时,都必须使用ParagraphStyleSpanStyle编写一些样式。不幸的是,这两个类都没有修改器来在每个文本(附加)之间添加一些填充。
这就是我现在得到的结果。 在每个文本的开头和结尾应该有一个小空格,将背景与字母分开: enter image description here 这是带有背景的代码:
val spanStyle = (
    MaterialTheme.typography.body1.copy(
     color = MaterialTheme.colors.onSurface,
     fontWeight = FontWeight.W400,
     fontSize = 17.sp,
     letterSpacing = 0.25.sp,
     background = MaterialTheme.colors.surface,
     baselineShift = BaselineShift(0.2f),
)).toSpanStyle()

buildAnnotatedString {
    withStyle(style = spanStyle) {
         append("I write text here with background")
    }
}

我已经检查了ParagraphStyle,但唯一与垂直间距相关的是lineHeight,它显然增加了每行的高度,但并没有增加它们之间的间距。

是否有办法在每个append()之间添加这个小间隔,以使背景不相连?

编辑: 这是我现在拥有的: enter image description here

这是我想要实现的效果,在内部和末尾添加水平间隔。 TextIndent不起作用,因为在开始背景和文本之间没有分离。 enter image description here


当您知道有背景时,为什么不在Modifier中添加“”空格或.padding()? - Jemshit Iskenderov
你是否正在使用等宽字体?如果是,添加空格会是一个好主意。 - Darkman
添加空格会创建太多不必要的空间,我不想要。另外,在SpanStyle中添加.padding()修饰符应该放在哪里?@JemshitIskenderov - Barrufet
遗憾的是,我没有使用等宽字体,如果你指的是要使用letterSpacing,我认为这不是一个好主意 @Darkman - Barrufet
1个回答

1
我认为使用系统方法不可能实现,但是您可以手动绘制背景。
我只添加了样例代码,有关实现的更多详细信息请参见this answer
@Composable
fun TestScreen(
) {
    val baselineShiftMultiplier = 0.2f
    val lineHeightMultiplier = 1.7f
    val spanStyle = MaterialTheme.typography.body1.copy(
        color = MaterialTheme.colors.onSurface,
        fontWeight = FontWeight.W400,
        fontSize = 17.sp,
        letterSpacing = 0.25.sp,
        baselineShift = BaselineShift(baselineShiftMultiplier),
    )
    var selectedPartPaths by remember { mutableStateOf(Path()) }
    Text(
        buildAnnotatedString {
            withStyle(ParagraphStyle(lineHeight = spanStyle.fontSize * lineHeightMultiplier)) {
                append("I write text here\n")
                withStyle(style = spanStyle.toSpanStyle()) {
                    append("I write text here with background\n")
                    append("I write text here with background\n")
                }
                append("I write text here\n")
                withStyle(style = spanStyle.toSpanStyle()) {
                    append("I write text here with background\n")
                }
                append("I write text here\n")
            }
        },
        onTextLayout = { layoutResult ->
            selectedPartPaths = Path().apply {
                layoutResult.layoutInput.text.spanStyles.forEach { spanRange ->
                    val boundingBoxes = layoutResult
                        .getBoundingBoxesForRange(
                            start = spanRange.start,
                            end = spanRange.end
                        )
                    for (i in boundingBoxes.indices) {
                        val boundingBox = boundingBoxes[i]
                        addRect(
                            boundingBox.copy(
                                top = boundingBox.top + boundingBox.height * (1 - 1 / lineHeightMultiplier - baselineShiftMultiplier),
                            )
                        )
                    }
                }
            }
        },
        modifier = Modifier.drawBehind {
            drawPath(selectedPartPaths, style = Fill, color = Color.LightGray)
        }
    )
}

fun TextLayoutResult.getBoundingBoxesForRange(start: Int, end: Int): List<Rect> {
    var prevRect: Rect? = null
    var firstLineCharRect: Rect? = null
    val boundingBoxes = mutableListOf<Rect>()
    for (i in start..end) {
        val rect = getBoundingBox(i)
        val isLastRect = i == end

        // single char case
        if (isLastRect && firstLineCharRect == null) {
            firstLineCharRect = rect
            prevRect = rect
        }

        // `rect.right` is zero for the last space in each line
        // looks like an issue to me, reported: https://issuetracker.google.com/issues/197146630
        if (!isLastRect && rect.right == 0f) continue

        if (firstLineCharRect == null) {
            firstLineCharRect = rect
        } else if (prevRect != null) {
            if (prevRect.bottom != rect.bottom || isLastRect) {
                boundingBoxes.add(
                    firstLineCharRect.copy(right = prevRect.right)
                )
                firstLineCharRect = rect
            }
        }
        prevRect = rect
    }
    return boundingBoxes
}

结果:


抱歉,也许我没有正确解释,我的意思是指水平填充(开始、结束),所以会有一小段像这样的填充 -> '-我在这里写背景文字-' 其中'-'是小填充。我不设置空格,因为它占用太多空间。 - Barrufet
但也许我可以通过边界框来使其运行,我需要深入研究那个代码。 - Barrufet
@Barrufet 如果您需要移动背景,可以像我展示的那样使用边界框来实现,但如果您需要移动文本本身,则唯一的选择是使用ParagraphStyle.textIndent:然而,这只适用于行的开头。我仍然不确定您的结果应该是什么样子的。请更新您的问题并提供详细信息,包括预期结果的屏幕截图,您可以在任何图像编辑器中完成。 - Phil Dukhov
我已经更新了它,以达到我想要实现的结果,但遗憾的是,这个onTextLayout需要大量的工作,并且在每次重组时会使我的视觉UI出现延迟(是的,它会重新组合,因为背景颜色会变成其他颜色)。我认为这不是一个好主意,但知道这个存在也是好事。 - Barrufet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接