Android 绘制文本的一些方法
- 转载部分于
- Canvas 绘制文字的方式
-
Paint 对文字绘制的辅助
- setTextSizefloat textSize 设置文字大小
- setTypefaceTypeface typeface 设置字体
- setFakeBoldTextboolean fakeBoldText 是否使用伪粗体
- setStrikeThruTextboolean strikeThruText 是否加删除线
- setUnderlineTextboolean underlineText 是否加下划线
- setTextSkewXfloat skewX 设置文字横向错切角度其实就是文字倾斜度的啦
- setTextScaleXfloat scaleX 设置文字横向放缩也就是文字变胖变瘦
- setLetterSpacingfloat letterSpacing 设置字符间距默认值是 0
- setFontFeatureSettingsString settings 用 CSS 的 font-feature-settings 的方式来设置文字
- setTextAlignPaintAlign align 设置文字的对齐方式
- setTextLocaleLocale locale setTextLocalesLocaleList locales 地区设置
- float getFontSpacing 获取推荐的行距
- FontMetircs getFontMetrics 获取 Paint 的 FontMetrics
- float measureTextString text 测量文字的宽度并返回
- getTextWidthsString text float widths 获取字符串中每个字符的宽度并把结果填入参数 widths
- int breakText 测量文字宽度的临近超限的位置截断文字
- 光标相关
转载部分于
Canvas 绘制文字的方式
drawText() 普通文本绘制
构造方法
/**
* 绘制普通的文本
* @param text 文字内容
* @param x 基线的 x 起点坐标
* @param y 基线的 y 起点坐标
* @param paint The paint used for the text (e.g. color, size, style)
*/
public void drawText(String text, float x, float y, Paint paint) {
}
事例代码
String text = "Hello word...";
canvas.drawText(text,200,100,mPaint);
drawTextOnPath() 根据Path绘制文字
构造方法
/**
* 根据Path路径 绘制文字
* @param text 文本内容
* @param path 路径
* @param hOffset 相对Path的 水平偏移
* @param vOffset 相对Path的 垂直偏移
* @param paint 画笔
*/
public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
float vOffset, @NonNull Paint paint) {
super.drawTextOnPath(text, path, hOffset, vOffset, paint);
}
事例代码
/** 初始化画笔 */
private void initPaint(){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(50);
}
@Override
protected void onDraw(Canvas canvas) {
String text = "Hello word...";
//根据path绘制
Path path = new Path();
path.lineTo(100,100);
path.lineTo(200,0);
//先绘制一条线,可以跟清晰的查看效果
canvas.drawPath(path,mPaint);
//绘制文本
canvas.drawTextOnPath(text,path,0,0,mPaint);
}
StaticLayout 多行文本绘制
构造方法
/**
* 根据Path路径 绘制文字
* @param source 文本内容
* @param TextPaint 画笔
* @param width 是文字区域的宽度,文字到达这个宽度后就会自动换行;
* @param align 是文字的对齐方向;
* @param spacingmult 是行间距的倍数,通常情况下填 1 就好;
* @param spacingadd 是行间距的额外增加值,通常情况下填 0 就好;
* @param includeadd 是指是否在文字上下添加额外的空间,来避免某些过高的字符的绘制出现越界。
*/
public StaticLayout(CharSequence source, TextPaint paint,
int width,
Alignment align, float spacingmult, float spacingadd,
boolean includepad) {
this(source, 0, source.length(), paint, width, align,
spacingmult, spacingadd, includepad);
}
事例代码
String text1 = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";
StaticLayout staticLayout1 = new StaticLayout(text1, paint, 600,
Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
String text2 = "a\nbc\ndefghi\njklm\nnopqrst\nuvwx\nyz";
StaticLayout staticLayout2 = new StaticLayout(text2, paint, 600,
Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
...
canvas.save();
canvas.translate(50, 100);
staticLayout1.draw(canvas);
canvas.translate(0, 200);
staticLayout2.draw(canvas);
canvas.restore();
效果图
Paint 对文字绘制的辅助
setTextSize(float textSize) 设置文字大小
paint.setTextSize(18);
canvas.drawText(text, 100, 25, paint);
paint.setTextSize(36);
canvas.drawText(text, 100, 70, paint);
paint.setTextSize(60);
canvas.drawText(text, 100, 145, paint);
paint.setTextSize(84);
canvas.drawText(text, 100, 240, paint);
setTypeface(Typeface typeface) 设置字体。
paint.setTypeface(Typeface.DEFAULT);
canvas.drawText(text, 100, 150, paint);
paint.setTypeface(Typeface.SERIF);
canvas.drawText(text, 100, 300, paint);
paint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "Satisfy-Regular.ttf"));
canvas.drawText(text, 100, 450, paint);
setFakeBoldText(boolean fakeBoldText) 是否使用伪粗体。
String text = "a\nbc\ndefghi\njklm\nnopqrst\nuvwx\nyz";
...
canvas.drawText(text, 50, 100, paint);
setStrikeThruText(boolean strikeThruText) 是否加删除线。
paint.setStrikeThruText(true);
canvas.drawText(text, 100, 150, paint);
setUnderlineText(boolean underlineText) 是否加下划线。
paint.setUnderlineText(true);
canvas.drawText(text, 100, 150, paint);
setTextSkewX(float skewX) 设置文字横向错切角度。其实就是文字倾斜度的啦。
paint.setTextSkewX(-0.5f);
canvas.drawText(text, 100, 150, paint);
setTextScaleX(float scaleX) 设置文字横向放缩。也就是文字变胖变瘦。
paint.setTextScaleX(1);
canvas.drawText(text, 100, 150, paint);
paint.setTextScaleX(0.8f);
canvas.drawText(text, 100, 230, paint);
paint.setTextScaleX(1.2f);
canvas.drawText(text, 100, 310, paint);
setLetterSpacing(float letterSpacing) 设置字符间距。默认值是 0。
paint.setLetterSpacing(0.2f);
canvas.drawText(text, 100, 150, paint);
setFontFeatureSettings(String settings) 用 CSS 的 font-feature-settings 的方式来设置文字。
paint.setFontFeatureSettings("smcp"); // 设置 "small caps"
canvas.drawText("Hello HenCoder", 100, 150, paint);
setTextAlign(Paint.Align align) 设置文字的对齐方式。
一共有三个值:LEFT CETNER 和 RIGHT。默认值为 LEFT。
paint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(text, 500, 150, paint);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, 500, 150 + textHeight, paint);
paint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(text, 500, 150 + textHeight * 2, paint);
setTextLocale(Locale locale) / setTextLocales(LocaleList locales) 地区设置
设置绘制所使用的 Locale。
Locale 直译是「地域」,其实就是你在系统里设置的「语言」或「语言区域」(具体名称取决于你用的是什么手机),比如「简体中文(中国)」「English (US)」「English (UK)」。有些同源的语言,在文化发展过程中对一些相同的字衍生出了不同的写法(比如*和日本对于某些汉字的写法就有细微差别。注意,不是繁体和简体这种同音同义不同字,而真的是同样的一个字有两种写法)。系统语言不同,同样的一个字的显示就有可能不同。你可以试一下把自己手机的语言改成日文,然后打开微信看看聊天记录,你会明显发现文字的显示发生了很多细微的变化,这就是由于系统的 Locale 改变所导致的。
另外,由于 Android 7.0 ( API v24) 加入了多语言区域的支持,所以在 API v24 以及更高版本上,还可以使用 setTextLocales(LocaleList locales) 来为绘制设置多个语言区域。
float getFontSpacing() 获取推荐的行距。
即推荐的两行文字的 baseline 的距离。这个值是系统根据文字的字体和字号自动计算的。它的作用是当你要手动绘制多行文字(而不是使用 StaticLayout)的时候,可以在换行的时候给 y 坐标加上这个值来下移文字。
canvas.drawText(texts[0], 100, 150, paint);
canvas.drawText(texts[1], 100, 150 + paint.getFontSpacing, paint);
canvas.drawText(texts[2], 100, 150 + paint.getFontSpacing * 2, paint);
FontMetircs getFontMetrics() 获取 Paint 的 FontMetrics。
FontMetrics 是个相对专业的工具类,它提供了几个文字排印方面的数值:ascent, descent, top, bottom, leading。
参数里,text 是要测量的文字,start 和 end 分别是文字的起始和结束位置,bounds 是存储文字显示范围的对象,方法在测算完成之后会把结果写进 bounds。
“` java
paint.setStyle(Paint.Style.FILL);
canvas.drawText(text, offsetX, offsetY, paint);
paint.getTextBounds(text, 0, text.length(), bounds);
bounds.left += offsetX;
bounds.top += offsetY;
bounds.right += offsetX;
bounds.bottom += offsetY;
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(bounds, paint);
“`
float measureText(String text) 测量文字的宽度并返回。
canvas.drawText(text, offsetX, offsetY, paint);
float textWidth = paint.measureText(text);
canvas.drawLine(offsetX, offsetY, offsetX + textWidth, offsetY, paint);
getTextWidths(String text, float[] widths) 获取字符串中每个字符的宽度,并把结果填入参数 widths。
获取字符串中每个字符的宽度,并把结果填入参数 widths。
这相当于 measureText() 的一个快捷方法,它的计算等价于对字符串中的每个字符分别调用 measureText() ,并把它们的计算结果分别填入 widths 的不同元素。
getTextWidths() 同样也有好几个变种,使用大同小异,不再介绍。
int breakText(…) 测量文字宽度的,临近超限的位置截断文字
这个方法也是用来测量文字宽度的。但和 measureText() 的区别是, breakText() 是在给出宽度上限的前提下测量文字的宽度。如果文字的宽度超出了上限,那么在临近超限的位置截断文字。
int measuredCount;
float[] measuredWidth = {0};
// 宽度上限 300 (不够用,截断)
measuredCount = paint.breakText(text, 0, text.length(), true, 300, measuredWidth);
canvas.drawText(text, 0, measuredCount, 150, 150, paint);
// 宽度上限 400 (不够用,截断)
measuredCount = paint.breakText(text, 0, text.length(), true, 400, measuredWidth);
canvas.drawText(text, 0, measuredCount, 150, 150 + fontSpacing, paint);
// 宽度上限 500 (够用)
measuredCount = paint.breakText(text, 0, text.length(), true, 500, measuredWidth);
canvas.drawText(text, 0, measuredCount, 150, 150 + fontSpacing * 2, paint);
// 宽度上限 600 (够用)
measuredCount = paint.breakText(text, 0, text.length(), true, 600, measuredWidth);
canvas.drawText(text, 0, measuredCount, 150, 150 + fontSpacing * 3, paint);
breakText() 的返回值是截取的文字个数(如果宽度没有超限,则是文字的总个数)。参数中, text 是要测量的文字;measureForwards 表示文字的测量方向,true 表示由左往右测量;maxWidth 是给出的宽度上限;measuredWidth 是用于接受数据,而不是用于提供数据的:方法测量完成后会把截取的文字宽度(如果宽度没有超限,则为文字总宽度)赋值给 measuredWidth[0]。
这个方法可以用于多行文字的折行计算。
breakText() 也有几个重载方法,使用大同小异,不再介绍。
光标相关
getRunAdvance(….) 计算出某个字符处光标的 x 坐标
对于一段文字,计算出某个字符处光标的 x 坐标。 start end 是文字的起始和结束坐标;contextStart contextEnd 是上下文的起始和结束坐标;isRtl 是文字的方向;offset 是字数的偏移,即计算第几个字符处的光标。
int length = text.length();
float advance = paint.getRunAdvance(text, 0, length, 0, length, false, length);
canvas.drawText(text, offsetX, offsetY, paint);
canvas.drawLine(offsetX + advance, offsetY - 50, offsetX + advance, offsetY + 10, paint);
其实,说是测量光标位置的,本质上这也是一个测量文字宽度的方法。上面这个例子中,start 和 contextStart 都是 0, end contextEnd 和 offset 都等于 text.length()。在这种情况下,它是等价于 measureText(text) 的,即完整测量一段文字的宽度。而对于更复杂的需求,getRunAdvance() 能做的事就比 measureText() 多了。
// 包含特殊符号的绘制(如 emoji 表情)
String text = "Hello HenCoder \uD83C\uDDE8\uD83C\uDDF3" // "Hello HenCoder ����"
...
float advance1 = paint.getRunAdvance(text, 0, length, 0, length, false, length);
float advance2 = paint.getRunAdvance(text, 0, length, 0, length, false, length - 1);
float advance3 = paint.getRunAdvance(text, 0, length, 0, length, false, length - 2);
float advance4 = paint.getRunAdvance(text, 0, length, 0, length, false, length - 3);
float advance5 = paint.getRunAdvance(text, 0, length, 0, length, false, length - 4);
float advance6 = paint.getRunAdvance(text, 0, length, 0, length, false, length - 5);
...
如上图,���� 虽然占了 4 个字符(\uD83C\uDDE8\uD83C\uDDF3),但当 offset 是表情中间处时, getRunAdvance() 得出的结果并不会在表情的中间处。为什么?因为这是用来计算光标的方法啊,光标当然不能出现在符号中间啦。
getOffsetForAdvance(…) 即第几个字符最接近这个坐标
给出一个位置的像素值,计算出文字中最接近这个位置的字符偏移量(即第几个字符最接近这个坐标)。
方法的参数很简单: text 是要测量的文字;start end 是文字的起始和结束坐标;contextStart contextEnd 是上下文的起始和结束坐标;isRtl 是文字方向;advance 是给出的位置的像素值。填入参数,对应的字符偏移量将作为返回值返回。
getOffsetForAdvance() 配合上 getRunAdvance() 一起使用,就可以实现「获取用户点击处的文字坐标」的需求。
hasGlyph(String string) 字符串中是否是一个单独的字形
检查指定的字符串中是否是一个单独的字形 (glyph)。最简单的情况是,string 只有一个字母(比如 a)。
上一篇: canvas绘制矩形
下一篇: 【Dart】入门01-变量