Android Developers

Android 15 带来了一些文本/字体相关的改动,主要涉及中日韩本地化相关的工作。

支持 CJK 可变字体

从 Android 15 开始,中文、日语和韩语 (CJK) 语言的字体文件 NotoSansCJK 现已成为可变字体。可变字体为 CJK 语言的广告素材排版开辟了新的可能性。设计师可以探索更广泛的样式,并创建以前难以或无法实现的具有视觉冲击力的布局。

原生 Android 在中日韩地区使用的 NotoSansCJK 字体支持可变字重,基本上不会出现同一场景汉字与拉丁文粗细不一的场景了。

cjk-variable-font.png

汉字 Justify 两端对齐效果

还是中日韩汉字🤣,可以采用 JUSTIFICATION_MODE_INTER_CHARACTER 这一新的字符间距调整方式来让文本进行两端对齐,解决了 7 年前 Android O 引入 JUSTIFICATION_MODE_INTER_WORD 对齐方式、但对 CJK 文本无效这一历史遗留问题。

以往的 JUSTIFICATION_MODE_INTER_WORD 对齐方式通过拉伸文本中的空格实现两端对齐,中日韩书写习惯不同,文本中不会出现空格,所以不适用于这种场景。新增 JUSTIFICATION_MODE_INTER_CHARACTER 对齐方式,通过调整字符间距实现,实际效果也很丑就是了🙈。

justification.png

自动换行配置

Android 从 Android 13(API 级别 33)开始针对日语和韩语支持基于短语的换行符。不过,虽然基于短语的换行符可以提高短行文本的可读性,但不适用于较长的文本。在 Android 15 中,应用现在可以使用 LINE_BREAK_WORD_STYLE_AUTO 选项为短文本行应用基于短语的换行符。此选项用于选择最适合该文本的文字样式选项。

还是汉字!!!🤣,断行算法会将基于短语的日韩文单词是为不可分割的一个片段,提高短行文本的可读性。但对于长文本不适用

line-break-auto-short.png

line-break-auto-long.png

新日语 Hentaigana 字体

In Android 15, a new font file for old Japanese Hiragana (known as Hentaigana) is bundled by default. The unique shapes of Hentaigana characters can add a distinctive flair to artwork or design while also helping to preserve accurate transmission and understanding of ancient Japanese documents.

好像是艺术字,没太多关注

开发者开发

改进了 OpenType Variable Font API

优化了可变字体的创建逻辑,不需要再对字体一级一级地设置字重了,在字体下声明可变的轴即可。

  • 以前 ->

val oldTypeface = Typeface.CustomFallbackBuilder(
            FontFamily.Builder(
                Font.Builder(assets, "RobotoFlex.ttf")
                    .setFontVariationSettings("'wght' 400")
                    .setWeight(400)
                    .build())
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 100")
                        .setWeight(100)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 200")
                        .setWeight(200)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 300")
                        .setWeight(300)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 500")
                        .setWeight(500)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 600")
                        .setWeight(600)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 700")
                        .setWeight(700)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 800")
                        .setWeight(800)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 900")
                        .setWeight(900)
                        .build()
                ).build()
        ).build()
  • 现在 ->

val newTypeface = Typeface.CustomFallbackBuilder(
            FontFamily.Builder(
                Font.Builder(assets, "RobotoFlex.ttf").build())
                    .buildVariableFamily())
    .build()

细化换行符控件

可以在文本中添加 <nobreak> 标记让文本在断行时尽可能不在这之间断开

<resources>
    <string name="pixel8pro">The power and brains behind Pixel 8 Pro.</string>
</resources>

line-breaks-none.png

<resources>
    <string name="pixel8pro">The power and brains behind <nobreak>Pixel 8 Pro.</nobreak></string>
</resources>

line-breaks-included.png