在 Jetpack Compose 中通过字体的上升而不是基线对齐两个文本

Align two texts by font's ascent instead of baseline in Jetpack Compose

我知道如何将 Jetpack Compose 中的文本与基线对齐。

但现在我需要将两个不同大小的文本对齐,这些文本在 Row 中由这两种字体中较大的 ascent 对齐。如果有意义的话,我想将其视为“按最高基线”对齐两个文本。 Modifier.align(Alignment.Top) 不起作用,因为它不会按上升对齐,而是按布局的顶部对齐,然后文本在顶部未正确对齐。

我试着看看如何做到这一点,但显然没有现成的功能或修改器?我什至没有找到在 Compose 中访问文本上升 属性 等的方法。所以不确定这怎么可能?

感谢任何提示! :)

编辑:这是使用Alignment.Top时的样子。但我希望这两个文本在顶部对齐。

一种解决方法是您可以根据需要调整 y 轴偏移修改器。

Text(text = "Second", modifier = Modifier.offset(x = 0.dp, y = 5.dp))

如果您想根据自己的需要增加第一个文本,您也可以将偏移量设置为负值。

可以使用 onTextLayout Text 参数检索有关文本布局的所有信息。在这种情况下,您需要一个线宽,可以使用 getLineBottom 检索,以及一个实际字体大小,可以在 layoutInput.style.fontSize.

中找到

我同意,如果您可以使用一些简单的方法来做到这一点会更容易,所以我为您的 feature request 加了星标,但现在您可以通过以下方式计算它:

onTextLayout = { textLayoutResult ->
    val ascent = textLayoutResult.getLineBottom(0) - textLayoutResult.layoutInput.run {
        with(density) {
            style.fontSize.toPx()
        }
    }
},

对齐两个文本的完整示例:

val ascents = remember { mutableStateMapOf<Int, Float>() }
val texts = remember {
    listOf(
        "Big text" to 80.sp,
        "Small text" to 20.sp,
    )
}
Row(
    Modifier
        .drawBehind {
            ascents.maxOfOrNull { it.value }?.let {
                drawLine(Color.Red, Offset(0f, it), Offset(size.width, it))
            }
        }
) {
    texts.forEachIndexed { i, info ->
        Text(
            info.first,
            fontSize = info.second,
            onTextLayout = { textLayoutResult ->
                ascents[i] = textLayoutResult.getLineBottom(0) - textLayoutResult.layoutInput.run {
                    with(density) {
                        style.fontSize.toPx()
                    }
                }
            },
            modifier = Modifier
                .alpha(if (ascents.count() == texts.count()) 1f else 0f)
                .layout { measurable, constraints ->
                    val placeable = measurable.measure(constraints)
                    val maxAscent = ascents.maxOfOrNull { it.value } ?: 0f
                    val ascent = ascents[i] ?: 0f
                    val yOffset = if (maxAscent == ascent) 0 else (maxAscent - ascent).toInt()
                    layout(placeable.width, placeable.height - yOffset) {
                        placeable.place(0, yOffset)
                    }
                }
        )
    }
}

结果: