Android:TextView的Layout创建过程

TextView组件,使用频率非常高,虽然使用起来比较简单,但是它的实现其实是一个复杂的过程。它对文字的管理是通过

Layout实现的。TextView内部会根据不同的设置,创建不同的Layout,总共有三种。

DynamicLayout:用在EditText或者TextView中设置的是Spannable类型的文字(比如ClickSpanURL等)。

BoringLayout:常用在处理单行文本。(所有字符必须是LTR[left-to-right]

StaticLayout:这个是默认的TextViewLayout,用在文字不会被改变的状态下。

TextView中有一个Layout类型的属性。

<code>private Layout mLayout;/<code>

那么它是在什么时候被创建的呢?我们就从measure说起。

<code>if (mLayout == null) {
makeNewLayout(want, hintWant, boring, hintBoring,
width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
}/<code>

measure方法中,会判断layout是否已经存在,如果不存在,就会通过makeNewLayout来创建。

<code>/**
* @param wantWidth 组件布局需要的宽度
* @param hintWidth hint的宽度
* @param boring 组件的度量信息
* @param hintBoring hint的度量信息
* @param ellipsisWidth 带上省略号需要的宽度,这个不包括左右的padding
* @param bringIntoView 如果设置为true,会注册一个绘制前的回调,
* 在view的tree结构被绘制前触发onPreDraw
*/
protected void makeNewLayout(int wantWidth, int hintWidth,
BoringLayout.Metrics boring,
BoringLayout.Metrics hintBoring,
int ellipsisWidth, boolean bringIntoView)/<code>

这个方法中又通过makeSingleLayout创建

layout

<code>mLayout = makeSingleLayout(wantWidth, boring, ellipsisWidth, alignment,
shouldEllipsize,effectiveEllipsize,
effectiveEllipsize == mEllipsize);/<code>

shouldEllipsize表示如果蚊子太多,显示不下,是否处理省略号的显示。

<code>boolean shouldEllipsize = mEllipsize != null && getKeyListener() == null;

//对于非编辑组件,getKeyListener一般为null/<code>

如果你设置了mEllipsize属性(省略号显示的位置)并且key的监听存在,那就是true

<code>protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth,
Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize,
boolean useSaved) {
Layout result = null;
//对于Spannable类型的,创建动态布局
if (mText instanceof Spannable) {
result = new DynamicLayout(......);
} else {
if (boring == UNKNOWN_BORING) {
//检查是否可以用BoringLayout
boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
......
}
//如果boring不为空,那么就要把测量结果和实际的显示区域进行比较,来确定是否可以单行显示
if (boring != null) {

//如果测量宽度不大于需要的宽度,
//并且设置了省略号位置或者测量宽度不大于带省略号时的宽度
if (boring.width <= wantWidth
&& (effectiveEllipsize == null || boring.width <= ellipsisWidth)) {
......
}
//或者需要处理省略号,并且宽度满足
else if (shouldEllipsize && boring.width <= wantWidth) {
......
}
}
}
//如果上面的条件都不满足,就会创建StaticLayout
if (result == null) {
//创建StaticLayout
StaticLayout.Builder builder = StaticLayout.Builder.obtain(......);
//设置省略号的显示样式及宽度
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
}
result = builder.build();
}
return result;
}/<code>

首先,先判断组件文本是否符合Spannable类型,如果是,则创建动态布局DynamicLayout

否则,通过BoringLayout.isBoring进行测量。意思就是,如果这些文字都显示在一行中,那么需要多大的显示区域,会把

Metrics类型的度量数据返回来。有了这个数据,那么接着就要用测量数据和实际布局中的显示区域进行比较,看看能否容纳测量结果。

如果可以,那么就返回这个 BoringLayout

如果放不下,就认为不能使用BoringLayout布局进行显示了,那就创建一个静态布局。

好了,这样Layout就创建好了,这里是大概的流程,里面具体的实现,后面会继续分析。


分享到:


相關文章: