Android StackLayout简单应用

初识StaticLayout是在一个需要计算TextView高度的时候,计算完高度后对TextView进行分页显示。为此我仔细观看了TextView中计算高度的部分,并从中找到了答案

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    // 篇幅太长,我们略过宽度部分,高度是由getDesiredHeight()来计算的
    ... ...

    if (heightMode == MeasureSpec.EXACTLY) {
        // Parent has told us how big to be. So be it.
        height = heightSize;
        mDesiredHeightAtMeasure = -1;
    } else {
        int desired = getDesiredHeight();

        height = desired;
        mDesiredHeightAtMeasure = desired;

        if (heightMode == MeasureSpec.AT_MOST) {
            height = Math.min(desired, heightSize);
        }
    }

    ... ...
    setMeasuredDimension(width, height);
}

private int getDesiredHeight() {
    return Math.max(
            getDesiredHeight(mLayout, true),
            getDesiredHeight(mHintLayout, mEllipsize != null));
}

private int getDesiredHeight(Layout layout, boolean cap) {
    if (layout == null) {
        return 0;
    }

    /*
    * Don't cap the hint to a certain number of lines.
    * (Do cap it, though, if we have a maximum pixel height.)
    */
    int desired = layout.getHeight(cap);

    final Drawables dr = mDrawables;
    if (dr != null) {
        desired = Math.max(desired, dr.mDrawableHeightLeft);
        desired = Math.max(desired, dr.mDrawableHeightRight);
    }

    int linecount = layout.getLineCount();
    final int padding = getCompoundPaddingTop() + getCompoundPaddingBottom();
    desired += padding;

    if (mMaxMode != LINES) {
        desired = Math.min(desired, mMaximum);
    } else if (cap && linecount > mMaximum && (layout instanceof DynamicLayout
            || layout instanceof BoringLayout)) {
        desired = layout.getLineTop(mMaximum);

        if (dr != null) {
            desired = Math.max(desired, dr.mDrawableHeightLeft);
            desired = Math.max(desired, dr.mDrawableHeightRight);
        }

        desired += padding;
        linecount = mMaximum;
    }

    if (mMinMode == LINES) {
        if (linecount < mMinimum) {
            desired += getLineHeight() * (mMinimum - linecount);
        }
    } else {
        desired = Math.max(desired, mMinimum);
    }

    // Check against our minimum height
    desired = Math.max(desired, getSuggestedMinimumHeight());

    return desired;
}

从上面的代码中我们可以看到TextView中文本的高度是由Lyout.getHeight(boolean)得到的,由此可见,文字的管理是通过Layout实现的。TextView内部会根据不同的设置,创建不同的Layout,总共有三种。

  • DynamicLayout:用在EditText或者TextView中设置的是Spannable类型的文字。
  • BoringLayout:常用在处理单行文本。
  • StaticLayout:这个是默认的TextViewLayout,用在文字不会被改变的状态下。。

在这里我们主要研究了StaticLayout,用它来计算文本高度。StaticLayout是基于Builder模式创建的

var layout = StaticLayout.Builder.obtain(source, start, end, paint, width)
        .setAlignment(alignment)
        .setTextDirection(textDir)
        .setLineSpacing(spacingAdd, spacingMult)
        .setIncludePad(includePad)
        .setBreakStrategy(breakStrategy)
        .setHyphenationFrequency(hyphenationFrequency)
        .setMaxLines(maxLine)
		.build()

主要参数

  • source是文本,startend分别是开始和结束位置。
  • paintTextPaint,用来绘制文本。
  • width是文本宽度,文字到达这个宽度后就会自动换行。
  • alignment是文本对齐方向,主要有ALIGN_NORMAL/ALIGN_CENTER/ALIGN_OPPOSITE
  • spacingAdd是行间距的额外增加值,默认为0。spacingmult是行间距的倍数,默认是1。
  • includePad是指是否在文字上下添加额外的空间,超出ascentdescent部分。
  • breakStrategy是换行策略,主要有BREAK_STRATEGY_SIMPLE/BREAK_STRATEGY_HIGH_QUALITY/BREAK_STRATEGY_BALANCED
  • maxLine是最大行数。

找到了TextView计算高度的方法后,我们自定义了一个文本显示控件,

class StaticLayoutView (context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
        View(context, attrs, defStyleAttr) {

    private var mStaticLayout: StaticLayout? = null

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    fun setLayout(layout: StaticLayout) {
        mStaticLayout = layout
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var height = mStaticLayout?.height ?: 0

        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        mStaticLayout?.draw(canvas)
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值