分析 TextView 应用 Spannable 风格后 ellipsize 属性失效

本文探讨了在TextView使用Spannable样式后,遇到的ellipsize属性无法正常工作的问题。通过深入分析TextView的绘制流程,发现是由于StaticLayout未正确计算ellipsis所导致,并给出了通过修改StaticLayout的mMaximumVisibleLineCount来解决问题的方法。

分析 TextView 应用 Spannable 风格后 ellipsize 属性失效


Author: nxliao(xtulnx@126.com)
Date:   2013-05-20

环境:

为使 TextView 在超小号字体情况下不因 descent 导致纯中文和纯英文显示不在同一水平线,使用 spannable 风格:

favorite.setText(info.getTitle(),TextView.BufferType.SPANNABLE);

参考:

http://stackoverflow.com/questions/14691511/textview-using-spannable-ellipsize-doesnt-work

问题:

使用 spannable 后,无法应用 android:ellipsize 属性。

分析:

  1. TextView.makeSingleLayout 构造 DynamicLayout 做为 mLayout;

  2. DynamicLayout.reflow 调用 StaticLayout.generate 解析文字布局;

  3. 通过 reflowed 获取 省略(ellipsis)内容:

        if (mEllipsize) {
            ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
            ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
        }
        mInts.insertAt(startline + i, ints);
    
  4. 经调试(在 TextView.draw 断点),修改 ((DynamicLayout)((TextView)v).mLayout) 之 mInts.mValues 的 [3]及[4],会响应到 mLayout.mText,而 mLayout.mText 即显示出来的内容。

    因此,问题应该出在第2步的结果。从数值均为0来看,可能是没有调用: StaticLayout.calculateEllipsis


StaticLayout.out

        boolean doEllipsis =
                    (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) &&
                            ellipsize != TextUtils.TruncateAt.MARQUEE) ||
                    (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
                            ellipsize == TextUtils.TruncateAt.END);

原因:

DynamicLayout.reflow 

    synchronized (sLock) {
        reflowed = sStaticLayout;
        sStaticLayout = null;
    }

    if (reflowed == null) {
        reflowed = new StaticLayout(null);
    } else {
        reflowed.prepare();
    }

默认构造中, StaticLayout.mMaximumVisibleLineCount = Integer.MAX_VALUE;

修改:

  1. 通过反射,修改 DynamicLayout.sStaticLayout.mMaximumVisibleLineCount = 1 即可。
  2. 这是一静态变量,改一次即可。
  3. 时机可选为 TextView.draw,试取 getLayout() 判断,或是预先构造 DynamicLayout 模拟计算,待创建静态成员 sStaticLayout 后修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值