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

来源:互联网 发布:阿里云 ssh账号密码 编辑:程序博客网 时间:2024/05/22 04:32

分析 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 后修改。