Android 13's new line-wrap strategy and optimizations for Japanese

foreword

Android 13 introduces a new wrapping strategy to the TextViewcontrol , while providing wrapping optimizations for Japanese. The system will wrap text according to the wrapping policy and Japanese phrase wrapping policy specified by the developer. This will make the text less cluttered, more organized, and easier to read.

Let's quickly learn this new feature from multiple perspectives such as API, actual combat, and adaptation methods.

Line break policy lineBreakStyle

Indicates the line break strategies can be used when calculating the text wrapping.

Constant Value Description
none 0 No line break style specific.
loose 1 Use the least restrictive rule for line-breaking.
normal 2 Indicate breaking text with the most comment set of line-breaking rules.
strict 3 ndicates breaking text with the most strictest line-breaking rules.

In fact, it comes from CSSthe line-breakattribute of , mainly for the CJKlanguage , that is, the newline rules provided by the three languages ​​of China, Japan and South Korea.

The attributes provided by Android are slightly different from CSS, but these three attributes are reserved loose, and the difference in attribute performance will be explained later through DEMO.normalstrict

Phrase wrapping policy lineBreakWordStyle

Specify the phrase-based line break can be used when calculating the text wrapping.

Constant Value Description
none 0 No line break word style specific.
phrase 1 Specify the phrase based breaking.

默认不生效,设置为 phrase 则生效。

动态设置

除了上述属性以外,TextView 理所应当地提供了 setLineBreakConfig() 来动态更新换行策略。

public void setLineBreakConfig (LineBreakConfig lineBreakConfig)
复制代码
Parameters
lineBreakConfig LineBreakConfig: the line break config for text wrapping. This value cannot be null.

LineBreakConfig

Android 13 新引入的承载换行策略的配置类,提供了上述属性相对应的常量以及返回策略所必要的 get 方法。

Constants
int LINE_BREAK_STYLE_LOOSEUse the least restrictive rule for line-breaking.
int LINE_BREAK_STYLE_NONENo line break style specified.
int LINE_BREAK_STYLE_NORMALIndicate breaking text with the most comment set of line-breaking rules.
int LINE_BREAK_STYLE_STRICTIndicates breaking text with the most strictest line-breaking rules.
int LINE_BREAK_WORD_STYLE_NONENo line break word style specified.
int LINE_BREAK_WORD_STYLE_PHRASEIndicates the line breaking is based on the phrased.
public int getLineBreakWordStyle ()
public int getLineBreakStyle ()
复制代码

实战

我们在中文和日语两种语言环境下提供一些测试文本,探究在不同换行策略下文本的实际表现。

换行策略的效果

换行策略的表现跟 CJK 语言里一些特定符号有关系,普通的文本表现上区别不是很明显。所以我们预设特别的一段文本在不同的显示宽度下的表现,来简要展现下不同规则下的差异。

  • 测试文本:【这里有个弯弯符号〜加“引号”然后最后有个问号?后面是普普通通一句话。】
class MainActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        LineBreakConfig().run {
            lineBreakStyle = LINE_BREAK_STYLE_NONE
            lineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE

            breakTestTextViewCSS.lineBreakConfig = this
            breakTestTextViewCSS_2.lineBreakConfig = this
        }
    }
    
    fun onButtonClick(view: View) {
        when (view.id) {
            R.id.break_btn -> breakTestTextViewCSS.lineBreakConfig.apply {
                lineBreakStyle =
                    when (breakTestTextViewCSS.lineBreakConfig.lineBreakStyle) {
                        LINE_BREAK_STYLE_NONE -> LINE_BREAK_STYLE_LOOSE
                        LINE_BREAK_STYLE_LOOSE -> LINE_BREAK_STYLE_NORMAL
                        LINE_BREAK_STYLE_NORMAL -> LINE_BREAK_STYLE_STRICT
                        LINE_BREAK_STYLE_STRICT -> LINE_BREAK_STYLE_NONE
                        else -> LINE_BREAK_STYLE_NONE
                    }
                breakTestTextViewCSS.lineBreakConfig = this
                breakTestTextViewCSS_2.lineBreakConfig = this
            }
        }
    }
}
复制代码
NONE LOOSE
NORMAL STRICT

可以看到

  • none 和 strict 策略下,符号的前方必须有文字,不能单独作为行首,而 loose 和 normal 策略则无此限制
  • 另外按照 css 的说明,只有在 strict 策略下,符号才允许作为行尾进行换行。但在 Android 13 上的测试发现,无论哪种策略都允许符号作为行尾换行,可能跟宽度配置有些关系
  • loose 策略下,符号 允许在行首单独出现,而其他模式不允许,前面必须要有其他文字才可换行

其他更详细的换行差异可以参考 w3c 的 css 换行说明,并进行实际的尝试。

短语换行策略效果

短语换行策略指的是日文情况下句尾遇到短语、助词如何换行,是固定换行还是短语整体另起一行。

  • 测试文本:【常に最新、最高のモバイル。Androidを開発した同じチームから。】

起初觉得只要展示的是日文都会应用该策略,便没有注意 App 当前语言是中文,以外发现画面中的日文文本没有按照预期进行换行。

class MainActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        LineBreakConfig().run {
            lineBreakStyle = LINE_BREAK_STYLE_NONE
            lineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE
            breakTestTextView.lineBreakConfig = this
        }
    }
    
    fun onButtonClick(view: View) {
        when (view.id) {
            R.id.phrase_break_btn -> breakTestTextView.lineBreakConfig.apply {
                lineBreakWordStyle =
                    if (breakTestTextView.lineBreakConfig.lineBreakWordStyle == LINE_BREAK_WORD_STYLE_PHRASE)
                        LINE_BREAK_WORD_STYLE_NONE
                    else LINE_BREAK_WORD_STYLE_PHRASE
                breakTestTextView.lineBreakConfig = this
            }
        }
    }
}
复制代码

需要当前语言是日语

当 App 语言切换为日语场景后,短语换行策略才会生效。

后来想想也是合理的,非日语的场景下用户能读懂日语的概率很低,在意换行的可能性更加小。系统没有必要耗费精力去判断文字是否是日文和进行换行。

而当 App 语言是日语的话,用户极高概率能读懂并且在乎短语换行的合理和连贯性,所以只在日语情况下生效则显得非常合理。

性能测试

可能有开发者会担心开启了短语换行是否造成性能的负担。通过覆写 TextView 并在 onMeasure() 里加入耗时统计,测定了展示 10000 个杂乱的日文文本下,短语换行策略开启与否的时间表现。

  • 设备版本是:Pixel 4 XL 13 Beta 1

  • workBreakStyle phrase(ms) none(ms)
    1 22 19
    2 22 20
    3 23 20
    4 28 21
    5 22 20
    6 22 25
    7 28 19
    8 22 20
    9 29 25
    10 22 25

可以看到即便是长度达到 10000 的超长文本,开启了短语换行策略的性能表现依旧没有什么明显劣化。在实际开发当中,显示长度达到 10000 的 TextView 文本的情况实属罕见。

我们可以断定短语换行策略对于文本显示的性能影响可以忽略不计。

另外,需要说明的是 TargetSDKVersion 不用升级到 33,所有的换行特性均可生效。

原理

目前只公开了 preview-1 的代码,搜索了一下没有发现 LineBreakConfig 相关的实现,后续等 Beta 版代码公开之后再作研究。

android.googlesource.com/platform/fr…

适配

  1. 思考下 App 是否需要开启新的换行策略
  2. 如果 App 支持日语的话,建议开启短语换行策略,优化日文的阅读体验
  3. 确定开启上述新策略的话,需要注意如下两点影响:
    • 画面布局是否发生错乱、切掉
    • 与已有的日文手动换行 \n 是否会发生冲突

总结

本新特性非常简单直白,我们可以使用换行策略去指定和 css 一致的换行规则,也可以针对日语指定换行友好的短语策略。

和 View 的一般用法无差,均有属性配置和动态更新两种方案。

另外,留意如下几点:

  • 该新特性不要求升级 TargetSDKVersion
  • 指定换行策略的话需要留意布局是否发生错乱、切掉的问题
  • 指定短语换行策略的话需要检查是否会和已有的手动换行发生冲突
    • 当前语言是日语环境下,短语换行策略才可以生效
    • 短语换行策略对于性能的影响可以忽略不计

参考资料

Guess you like

Origin juejin.im/post/7099054844404563982