Android:TextView的Layout创建过程

TextView组件,使用频率非常高,虽然使用起来比较简单,但是它的实现其实是一个复杂的过程。它对文字的管理是通过Layout实现的。TextView内部会根据不同的设置,创建不同的Layout,总共有三种。

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

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

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

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

private Layout mLayout;

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

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

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

/**
 * @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)

这个方法中又通过makeSingleLayout创建layout

mLayout = makeSingleLayout(wantWidth, boring, ellipsisWidth, alignment,
            shouldEllipsize,effectiveEllipsize, 
            effectiveEllipsize == mEllipsize);

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

boolean shouldEllipsize = mEllipsize != null && getKeyListener() == null;

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

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

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;
}

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

否则,通过BoringLayout.isBoring进行测量。意思就是,如果这些文字都显示在一行中,那么需要多大的显示区域,会把Metrics类型的度量数据返回来。有了这个数据,那么接着就要用测量数据和实际布局中的显示区域进行比较,看看能否容纳测量结果。

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bdmh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值