之前做 LeafLoadingView 的时候,进度到达 100 后,需要将风扇替换为文字。这里的文字当时还是让我头疼了一会的,不过最终用缩放解决了问题。这让我不禁想,安卓 sdk 中肯定有绘制 text 的 api 我不知道,否则绘制文字的时候难点太多了。如果要我自己实现一个简易版的 TextView 根本不可能。
机缘巧合的某天,我在 github 上看一个项目,正巧看到了他们实现一个自定义 View 时测量文本用的方法,看起来挺好用的,google 了一下,今天学习了。
测量单行文本
这个技能相信大部分有过自定义 View 经历的人都学习过了,如果你有一个单行文本需要测量,那么通常你可以使用 TextPaint
或者 Paint
来测量。
例如:
String text = "This is some text."
TextPaint myTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(0xFF000000);
float width = mTextPaint.measureText(text);
float height = -mTextPaint.ascent() + mTextPaint.descent();
同样的,由于是单行文本,我们也不需要做换行操作,因此只要直接利用 drawText 方法绘制上去就可以了。这样的需求十分简单,相信即使没有接触过自定义 TextView, 也可以很快完成。
如果你是在界面代码中需要测量文本长度的话,那么下面的代码或许可以帮到你:
//在界面代码中测量文本
// 1. 对于显示在已知 TextView 上的文本
Paint paint = textView.getPaint();
// 2. 对于普通的文本
Paint paint = new Paint();
//... 设置各种显示的属性
// 获取到 Paint 对象之后,剩下的测量方式,请参考上面的代码
测量多行文本 - StaticLayout
我们知道利用 drawText
方法绘制文字,是不会自动换行的。如果文本超出容器的限制,多余的部分在屏幕上是不会显示的。因此,如果要利用 drawText
绘制长文本,需要计算长度进行文本截取和换行绘制的操作。这个过程稍微想象一下就让人怠惰起来一点也没有干劲。
这里就该提到我之前说到的新学习的类了—— StaticLayout。StaticLayout 封装了许多有用的方法,同时它也支持自动换行。事实上,TextView 中也使用到了 StaticLayout。
StaticLayout 的构造器中需要传入许多参数,刚刚见到的时候可以说是一头雾水。下面让我们来介绍一下各个参数的含义:
StaticLayout(
CharSequence source, //1.需要分行的字符串
int bufstart, //2.需要分行的字符串从第几的位置开始
int bufend, //3.需要分行的字符串到哪里结束
TextPaint paint, //4.画笔对象
int outerwidth, //5.layout的宽度,字符串超出宽度时自动换行
Alignment align, //6.layout的对其方式,有ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE 三种
float spacingmult, //7.相对行间距,相对字体大小,1.5f表示行间距为1.5倍的字体高度
float spacingadd, //8.在基础行距上添加多少
boolean includepad, //9.是否包含文字上下的空余部分,在某些语言下,切割这些空余部分会导致显示不全,默认为true
TextUtils.TruncateAt ellipsize, //10.从什么位置开始省略 TextUtils.TruncateAt
int ellipsizedWidth, //11.超过多少开始省略,这个值仅用于省略,不影响 Layout 的宽度
int maxLine //12.最大行数
)
上面的参数如果觉得不够清楚,可以查看源码。在 api 23 之后,加入了 Builder 的链式构造,每个构造方法中都有参数的说明,查看十分方便。
构造好之后,就可以直接利用 getHeight
方法计算出 Layout 的高度了。
String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";
TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);
int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;
StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);
float height = myStaticLayout.getHeight();
以上。
感谢:
1.stackoverflow - How is StaticLayout used in Android?
2.Android - drawing multiline text on bitmap
3.Usability of BoringLayout