前面学习了
Android自定义View(一) – 初识
Android自定义View(二) – Paint详解
今天继续学习第三篇内容drawText(),本文是对第二篇文章中drawText的拓展,进行详细学习
本文计划根据HenCoder系列文章进行学习,所以代码风格及博文素材可能会摘自其中。
1.Canvas 绘制文字的方式
Canvas 的文字绘制方法有三个:drawText() drawTextRun() 和 drawTextOnPath()。
1.1 drawText(String text, float x, float y, Paint paint)
drawText() 是 Canvas 最基本的绘制文字的方法:给出文字的内容和位置, Canvas 按要求去绘制文字。
paint = new Paint();
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setTextSize(200);
.
if (paint == null || TextUtils.isEmpty(this.charSequence)){
return;
}
canvas.drawText(charSequence.toString(),20,200,paint);
方法的参数很简单: text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:
如果像绘制其他内容一样,设置(0,0),文字不会显示在屏幕左上角,直接显示在屏幕外,无法观察到。
附上一张图,应该能更清楚地表达:
这是为什么?为什么其它的 Canvas.drawXXX()
方法,都是以左上角作为基准点的,而 drawText()
却是文字左下方?
先别觉得日了狗,这种设计其实是有道理的。drawText()
参数中的 y
,指的是文字的基线( baseline ) 的位置。也就是这条线:
众所周知,不同的语言和文字,每个字符的高度和上下位置都是不一样的。要让不同的文字并排显示的时候整体看起来稳当,需要让它们上下对齐。但这个对齐的方式,不能是简单的「底部对齐」或「顶部对齐」或「中间对齐」,而应该是一种类似于「重心对齐」的方式。就像电线上的小鸟一样:
每只小鸟的最高点和最低点都不一样,但画面很平衡
而这个用来让所有文字互相对齐的基准线,就是基线( baseline )。 drawText()
方法参数中的 y
值,就是指定的基线的位置。
说完 y
值,再说说 x
值。从前面图中的标记可以看出来,「Hello HenCoder」绘制出来之后的 x
点并不是字母 “H” 左边的位置,而是比它的左边再往左一点点。那么这个「往左的一点点」是什么呢?
它是字母 “H” 的左边的空隙。绝大多数的字符,它们的宽度都是要略微大于实际显示的宽度的。字符的左右两边会留出一部分空隙,用于文字之间的间隔,以及文字和边框的间隔。就像这样:
用竖线标记出边界后的文字。
所以,明白为什么 x
坐标在 “H” 的左边再往左一点点的位置,而不是紧贴着 “H” 的左边线了吗?就是因为 “H” 的这个留出的空隙。
除了 drawText(text, x, y, paint)
之外, drawText()
还有几个重载方法,使用方式跟这个都差不多。
1.2 drawTextRun()
这部分对中英文没有作用,对一些特殊文字有作用,如果需要了解,参考原文中讲解HenCoder-drawText
1.3 drawTextOnPath()
沿着一条 Path 来绘制文字。这是一个耍杂技的方法。
path.addRect(200,300,600,800,Path.Direction.CW);
canvas.drawTextOnPath(charSequence.toString(),path,0,0,paint);
drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)
参数里,需要解释的只有两个: hOffset 和 vOffset。它们是文字相对于 Path 的水平偏移量和竖直偏移量,利用它们可以调整文字的位置。例如你设置 hOffset 为 5, vOffset 为 10,文字就会右移 5 像素和下移 10 像素。
1.4 StaticLayout
额外讲一个 StaticLayout
。这个也是使用 Canvas
来进行文字的绘制,不过并不是使用 Canvas
的方法。
Canvas.drawText()
只能绘制单行的文字,而不能换行。它:
- 不能在 View 的边缘自动折行
String text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";
...
canvas.drawText(text, 50, 100, paint);
到了 View 的边缘处,文字继续向后绘制到看不见的地方,而不是自动换行
- 不能在换行符
\n
处换行
String text = "a\nbc\ndefghi\njklm\nnopqrst\nuvwx\nyz";
...
canvas.drawText(text, 50, 100, paint);
在换行符
\n
的位置并没有换行,而只是加了个空格
如果需要绘制多行的文字,你必须自行把文字切断后分多次使用 drawText()
来绘制,或者——使用 StaticLayout
。
StaticLayout 并不是一个 View
或者 ViewGroup
,而是 android.text.Layout
的子类,它是纯粹用来绘制文字的。 StaticLayout 支持换行,它既可以为文字设置宽度上限来让文字自动换行,也会在 \n 处主动换行。
StaticLayout 的构造方法是 StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad),其中参数里:
width 是文字区域的宽度,文字到达这个宽度后就会自动换行;
align 是文字的对齐方向;
spacingmult 是行间距的倍数,通常情况下填 1 就好;
spacingadd 是行间距的额外增加值,通常情况下填 0 就好;
includeadd 是指是否在文字上下添加额外的空间,来避免某些过高的字符的绘制出现越界。
如果你需要进行多行文字的绘制,并且对文字的排列和样式没有太复杂的花式要求,那么使用 StaticLayout 就好。
2 Paint 对文字绘制的辅助
Paint 对文字绘制的辅助,有两类方法:设置显示效果的和测量文字尺寸的。
2.1 设置显示效果类
2.1.1 setTextSize(float textSize)
设置文字大小。
paint.setTextSize<