首先 AppCompatTextVIew 会持有 AppCompatTextHelper 这个帮助类,而这个帮助类,又去持有 AppCompatTextViewAutoSizeHelper,最终所有的逻辑都传递到 AppCompatTextViewAutoSizeHelper 中去处理。
所以操作的流程大概是这样的:
而 Autosizing 真实去测量并修改字体大小的逻辑,都在 autoSizeText() 方法中,我们只需要关心它在何时被调用,就能知道具体触发 Autosizing 的时机了。
第一个触发点,它会在 AppCompatTextView 的 onTextChanged() 方法中,直接调用 autoSizeText() 方法。
第二个触发点,会监听 AppCompatTextView 的 onLayout() 方法,在其中调用 AppCompatTextHelper 的 onLayout() 方法。
好了,两个时机都找到了,也验证了我们之前的猜想。
3.3 Autosizing 如何计算大小前面提到 Autosizing 实际上去修改 TextView 字体的方法,在 AppCompatTextViewAutoSizeHelper 的 autoSizeText() 方法中,这里我们先来看看这个方法的实现。
这一段逻辑,就是 Autosizing 中,很重要的一个逻辑。先来看看它大体上的流程。
使用它会使用 isAutoSizeEnabled() 方法,判断当前是否开启 Autosizing 。
判断 mNeedsAutoSizeText 是否为 true,此处判断是主要是看是否存在可变动的尺寸。
计算 TextView 本身的显示区域大小,存放在 TEMP_RECTF 中。
使用 findLargestTextSizeWhichFits() 获取到一个合适当前文本长度的最大尺寸值。
如果和当前 TextView 的 textSize 不一致,则使用 setTextSizeInternal() 将其设置回去。
大体步骤就是这样,接下来我们从细节出发看看它的具体实现。
首先是 isAutoSizeEnable() 方法,它去判断当前是否开启了 Autosizing,其实就是判断 mAutoSizeTextType 属性是否为 none。
而 mNeedsAutoSizeText 这个判断,本质上其实是为了判断 mAutoSizeTextSizesInPx 这个存放尺寸的数组里,是否有值,这个尺寸数组,在后面的 findLargestTextSizeWhichFits() 方法中会用到。
mAutoSizeTextSizesInPx 其实就是一个存放当前 TextView 预估能使用的尺寸数组,是被提前计算出来的,它会在对 Autosizing 受影响的相关的属性做出修改的时候,重新计算。例如:粒度(Granularity)、预设尺寸(PresetSizes)等变动,都会触发重新计算 mAutoSizeTextSizesInPx 的值。
TEMP_RECTF 就没有什么好说的了,无非就是从 TextView 的宽高和 Padding 等属性,计算出一个能用于显示 文本 区域大小。接下来就会去调用 findLargestTextSizeWhichFits() 方法,找到一个当前 文本 内容,最合适的字体大小。
这里逻辑也很清晰,就是使用一个循环,通过 suggestedSizeFitsInSpace() 方法判断取出来的尺寸是否合适。这里为了提高效率,使用了二分算法,去避免全部遍历 mAutoSizeTextSizesInPx 数组,从而提高效率。
接下来就是 suggestedSizeFitsInSpace() 方法,它会根据 TextView 的内容区域和 文本,判断当前给定的尺寸,是否能放的下这些内容。
这里首先使用了一个 TextPaint 对象 mTempTextPaint 来存放 TextView 的一些参数,然后根据 mTempTextPaint 去创建一个使用 StaticLayout 对象,来尝试对文本进行布局。
StaticLayout 是一个为不可编辑的文本布局的类,这意味着一旦布局完成,文本内容就不可以改变。
最终,就能确定,传递进行的字体大小,是否能完全显示在这个区域内。