如何在 Jetpack Compose 中为文本添加 dotted/dashed 下划线?

How do I make a dotted/dashed underline for Text in Jetpack Compose?

我正在尝试获取自定义 TextDecoration - DashUnderline。现有答案仅适用于一行,我需要为每一行文本添加虚线。

对于 TextView,我有一个 class,但我不知道如何将其转换为 Compose。

class DashedUnderlineSpan(
    textView: TextView, color: Int, thickness: Float, dashPath: Float,
    offsetY: Float, spacingExtra: Float
) :
    LineBackgroundSpan, LineHeightSpan {
    private val paint: Paint
    private val textView: TextView
    private val offsetY: Float
    private val spacingExtra: Float
    override fun chooseHeight(
        text: CharSequence, start: Int, end: Int, spanstartv: Int, v: Int,
        fm: Paint.FontMetricsInt
    ) {
        fm.ascent -= spacingExtra.toInt()
        fm.top -= spacingExtra.toInt()
        fm.descent += spacingExtra.toInt()
        fm.bottom += spacingExtra.toInt()
    }

    override fun drawBackground(
        canvas: Canvas, p: Paint, left: Int, right: Int, top: Int, baseline: Int,
        bottom: Int, text: CharSequence, start: Int, end: Int, lnum: Int
    ) {
        val lineNum = textView.lineCount
        for (i in 0 until lineNum) {
            val layout = textView.layout
            val path = android.graphics.Path()
            path.moveTo(layout.getLineLeft(i), layout.getLineBottom(i) - spacingExtra + offsetY)
            path.lineTo(layout.getLineRight(i), layout.getLineBottom(i) - spacingExtra + offsetY)
            canvas.drawPath(path, paint)
        }
    }

    init {
        paint = Paint()
        paint.color = color
        paint.style = Paint.Style.STROKE
        paint.pathEffect = DashPathEffect(floatArrayOf(dashPath, dashPath), 0f)
        paint.strokeWidth = thickness
        this.textView = textView
        this.offsetY = offsetY
        this.spacingExtra = spacingExtra
    }
}

我找到了解决方案:

var layout by remember { mutableStateOf<TextLayoutResult?>(null) }

Text(
    text = "История университета",
    style = MaterialTheme.typography.h3,
    color = Color.Black,
    onTextLayout = {
        layout = it
    },
    modifier = Modifier.drawBehind {

        layout?.let {
            val thickness = 5f
            val dashPath = 15f
            val spacingExtra = 4f
            val offsetY = 6f

            for (i in 0 until it.lineCount) {
                drawPath(
                    path = Path().apply {
                        moveTo(it.getLineLeft(i), it.getLineBottom(i) - spacingExtra + offsetY)
                        lineTo(it.getLineRight(i), it.getLineBottom(i) - spacingExtra + offsetY)
                    },
                    Color.Gray,
                    style = Stroke(width = thickness,
                        pathEffect = PathEffect.dashPathEffect(floatArrayOf(dashPath, dashPath), 0f)
                    )
                )
            }
        }
    }
)