Android 日常 | TextView 的 breakStrategy 属性是怎么回事?

7,674 阅读4分钟

封面图 by Lauren Peng on Unsplash

1. 简介

自 Andriod API 23(Android 6.0)起,TextView 新增了一个 breakStrategy 属性,这个属性用于控制将一段文本分割成多行时的折行策略,通俗的讲就是决定一行到底需要显示多少文本。

breakStrategy 既可以通过 TextView 的 xml 属性 android:breakStrategy设置,也可以通过 setBreakStrategy 方法来设置。可以设置的值只有三个,它们是 android.text.Layout 类的三个常量:

  • BREAK_STRATEGY_SIMPLE:对应 xml 属性 "simple"

  • BREAK_STRATEGY_HIGH_QUALITY:对应 xml 属性 "high_quality"

  • BREAK_STRATEGY_BALANCED :对应 xml 属性 "balanced"

2. 三种折行策略对比

2.1 BREAK_STRATEGY_SIMPLE

简单折行。这种策略会在每一行显示尽可能多的字符,直到这一行不能显示更多字符时才进行换行,同时这种策略下不会自动添加连词符(官方文档说,当一行只有一个单词并且宽度显示不下的情况下才会添加连词符,不过在测试过程中并没有看到连词符)。

在进行文本编辑时,后添加的文本不会影响前面文本的布局显示,比较适合可编辑的文本。EditText 默认的折行策略就是这种,因为可以避免在输入文本时由于布局刷新导致的字符跳动问题,保证用户的输入体验。

2.2 BREAK_STRATEGY_BALANCED

平衡折行。这个策略会尽可能保证一个段落的每一行的宽度相同,必要时会添加连词符。

2.3 BREAK_STRATEGY_HIGH_QUALITY

高质量折行。这个策略会针对整段文本的折行进行布局优化,必要时会自动添加连词符。和其他两种策略相比,这个策略会略微影响性能,并且需要更多时间进行文本布局。这个策略通常比较适合只读文本,TextView 的默认折行策略就是这种。

文字介绍没有图片来的直观,下面通过简单的例子来展示一下不同策略下段落折行情况的不同。

需要说明的是,对同一段文本分别设置三种策略并不一定会产生三种不同的布局表现,更多时候得到的是两种,其中有两种策略对应的布局是相同的。这里为了突出这三种策略下的布局差异,我选择了数字与 ImageSpan 混排的文本(这也是我遇到的导致布局异常的测试用例)。

BREAK_STRATEGY_SIMPLE 折行效果

BREAK_STRATEGY_SIMPLE 折行效果

BREAK_STRATEGY_HIGH_QUALITY 折行效果

BREAK_STRATEGY_BALANCED 折行效果

3. 源码粗析

TextView 通过 StaticLayout 或者 DynamicLayout 设置对应的折行策略,在最新的源码中,layout 又通过LineBreaker 进行折行操作。

LineBreaker 是 API 29 新增的,提供了computeLineBreaks 方法用于计算段落折行,计算结果被包装成在 LineBreaker.Result 类实例中,该类提供了一些方法来获取折行计算后的结果,比如 getLineCountgetLinewidth 等等。

如果对实现细节感兴趣,可以进一步对源码进行阅读,这里我只抛砖引玉的简单介绍。

4. 低版本表现

由于 breakStrategy 这个属性在 API 23 才被添加进来,因此有必要了解在低版本时文本折行策略。这样当我们使用这个属性时,可以做到心中有数,尽量避免兼容性导致的体验问题。

先说结论,根据我(并不严谨)的测试,在低版本时 TextView 采用的折行策略是 simple

测试过程:我使用了同一款机型的模拟器,一个运行系统版本为 19,一个运行系统版本为24,在显示内容相同的情况下,对比发现,低版本布局与高版本设置simple时的布局一致(这段文本在折行策略为balanced和high_quality时均表现为不同布局)。

API 19 折行效果

API 24 BREAK_STRATEGY_SIMPLE 折行效果

5. 总结

从 API 23 开始,TextView 新增了 breakStrategy 属性用于控制将一段文本分为多行时的折行策略,三种策略分别为简单折行、平衡折行和高质量折行。

其中简单折行致力于让一行显示尽可能多的文本;平衡折行侧重于让一段的多行文本宽度尽量一致;高质量折行则会从段落整体对文本布局进行优化,相比其他两种对性能消耗更多。

TextView 默认的折行策略是 high_quality,而 EditText 默认的折行策略是 simple,主要是为了保证输入体验,防止输入过程中出现字符跳动。

从源码看,breakStrategy 主要是通过 StaticLayout 生效,而在最新版本的源码中,StaticLayout 内部又是通过LineBreaker(API 29 新增)来进行段落的分行操作的。

在 API 23 以前,文本的折行策略采用的是高版本中的 simple。

breakStrategy 这个属性相比其他属性来说可能并不是那么常用,但是当你发现 TextView 的折行表现不及你的预期(特别是处理中英文混排、文字图片混排等情况)时,通过改变这个属性的值,可能就会获得你想要的结果。

推荐阅读