分析 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 属性。
分析:
-
TextView.makeSingleLayout 构造 DynamicLayout 做为 mLayout;
-
DynamicLayout.reflow 调用 StaticLayout.generate 解析文字布局;
-
通过 reflowed 获取 省略(ellipsis)内容:
if (mEllipsize) { ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i); ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i); } mInts.insertAt(startline + i, ints);
-
经调试(在 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;
修改:
- 通过反射,修改 DynamicLayout.sStaticLayout.mMaximumVisibleLineCount = 1 即可。
- 这是一静态变量,改一次即可。
- 时机可选为 TextView.draw,试取 getLayout() 判断,或是预先构造 DynamicLayout 模拟计算,待创建静态成员 sStaticLayout 后修改。