PAYATHON 2026

为什么 TextAlign.Justify 在模拟器上生效,在 Android 真机上却左对齐?

数据小许

结论

代码中已经设置了 TextAlign.Justify,但现有信息不足以确定真机上显示为左对齐的原因。Android 从 API level 26 起就提供了词间两端对齐,不能直接把问题归因于 Android 14 不支持。Android Layout 文档

建议先确认两台设备实际显示的字符串是否相同,再使用固定文本和固定宽度进行对照。目前缺少 R.string.home_long_text 的内容、Compose 版本和真机型号,无法判断差异是由文本内容、排版条件还是设备实现造成的。

先区分自动换行和显式换行

TextAlign.Justify 会拉伸因可用宽度不足而自动换行的行。以显式换行结束的行按 Start 对齐,段落最后一行也不会被强行拉满。对于从左向右书写的文本,这通常表现为左对齐。TextAlign 源码说明

如果字符串在每个显示行末尾都包含 \n,就可能出现每一行都不拉伸的现象。原问题没有提供字符串内容,因此还不能断定是否存在多余的换行。

可以先检查运行时得到的实际字符串:

val text = stringResource(R.string.home_long_text)

LaunchedEffect(text) {
    android.util.Log.d(
        "JustifyCheck",
        text.replace("\r", "\\r").replace("\n", "\\n")
    )
}

比较模拟器和真机的输出,确认语言、文字、空格和换行是否一致。尤其要检查不同语言的 values-* 目录是否为同一个资源提供了不同内容。如果确实为了控制显示行而插入了换行,可以删除这些换行,让布局自动折行;有语义的段落分隔则应保留。

用固定文本和宽度缩小范围

暂时绕开字符串资源,移除 LineBreak.Paragraph 和 Hyphens.Auto,只保留两端对齐:

@Composable
fun JustifyProbe() {
    val sample = (
        "This is a sample paragraph with ordinary spaces between words. " +
        "It should wrap automatically within the available width. "
    ).repeat(8)

    Text(
        text = sample,
        modifier = Modifier
            .width(240.dp)
            .padding(16.dp),
        style = TextStyle(
            textAlign = TextAlign.Justify
        )
    )
}

将组件放在能够容纳其宽度的容器中,在两台设备上运行同一份构建产物,并尽量保持字体和字体缩放一致。这段文本没有显式换行,词与词之间也使用了普通空格,适合用来观察自动折行后的对齐效果。

根据运行结果继续排查:

  • 两台设备都正常:逐项恢复原始字符串、原始宽度、LineBreak.Paragraph 和 Hyphens.Auto,观察从哪一步开始出现差异。
  • 固定文本正常,原始字符串异常:重点检查换行、空格类型、文本语言和资源内容。
  • 固定文本在真机上仍异常:记录真机型号、系统构建号、Compose BOM 或 ui-text 版本,并在其他设备上运行同一示例,进一步判断问题范围。

这些步骤用于定位原因,示例本身并不代表原问题已经修复。

检查文本是否适合词间拉伸

Android 上 Compose 的 TextAlign.Justify 映射为 JUSTIFICATION_MODE_INTER_WORD,通过拉伸词间空白实现对齐。如果内容主要是没有空格的连续字符、长 URL 或单个超长标识符,就不能预期它与普通英文段落呈现相同的效果。Compose AndroidParagraph 源码

LineBreak.Paragraph 和 Hyphens.Auto 分别影响断行和自动断词,不能保证每一行都被拉满。先单独验证 TextAlign.Justify,更容易看清差异来自哪里。

宽度设置需要怎样调整?

对齐范围是 Text 的内容区域。原代码设置了 padding(20.dp),因此文本应在扣除内边距后的宽度内对齐,不会贴到屏幕两侧。

在通常的有界父布局中,fillMaxSize() 已经占满可用宽度,后面一般不需要再次调用 fillMaxWidth()。不过,删除它并不能作为解决真机差异的依据。

下一步应取得两台设备实际加载的 home_long_text,再运行固定文本示例。没有这两项对照结果,不宜认定是代码写错或某个系统缺陷。

备注:内容仅供参考。