01.3 精通自定义 View 之绘图基础——文字

返回自定义 View 目录

1.3.1 Paint 设置

Paint 与文字相关的设置方法有如下几个:

  • 普通设置
1
2
3
4
5
6
7
8
9
10
// 设置画笔宽度
paint.setStrokeWidth (5);
// 指定是否使用抗锯齿功能。如果使用,则会使绘图速度变慢
paint.setAntiAlias(true);
// 绘图样式,对于文字和几何图形都有效
paint.setStyle(Paint.Style.FILL);
// 设置文字对齐方式: Align.CENTER、Align.LEFT、Align.RIGHT
paint.setTextAlign(Align.CENTER);
// 设置文字大小
paint.setTextSize(12);
  • 样式设置
1
2
3
4
5
6
7
8
// 设置是否为粗体文字
paint.setFakeBoldText(true);
// 设置下画线
paint.setUnderlineText(true);
// 设置字体水平倾斜度,普通斜体字设为 -0.25,右为负左为正
paint.setTextSkewX((float) -0.25);
// 设置带有删除线效果
paint.setStrikeThruText(true);
  • 其他设置
1
2
// 只会将水平方向拉伸,高度不会变
paint.setTextScaleX(2);

1. 填充样式的区别

paint.setStyle() 函数对文字和几何图形都有效。下面就来看看不同的填充样式对文字的影响:

1
2
3
4
5
6
7
8
9
10
11
12
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(5);
mPaint.setAntiAlias(true);
mPaint.setTextSize(100);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawText("先小涛 STROKE", 100, 200, mPaint);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawText("先小涛 FILL", 100, 320, mPaint);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawText("先小涛 FILL_AND_STROKE", 100, 440, mPaint);

效果图如下:
字体填充样式

2. setTextAlign() 函数

1
public void setTextAlign(Align align)

用于设置所要绘制的字符串与起始点的相对位置。参数 Align align 的取值如下:

  • Align.LEFT:居左绘制,即通过 drawText() 函数指定的起始点在最左侧,文字从起始点位置开始绘制。
  • Align.CENTER:居中绘制,即通过 drawText() 函数指定的起始点在文字中间位置。
  • Align.RIGHT:居右绘制,即通过 drawText() 函数指定的起始点在文字右侧位置。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mLinePaint = new Paint();
mLinePaint.setColor(Color.BLUE);
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(5);
mPaint.setAntiAlias(true);
mPaint.setTextSize(80);
canvas.drawCircle(400, 100, 5, mLinePaint);
canvas.drawLine(400, 100, 400, 300, mLinePaint);
mPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("先小涛", 400, 100, mPaint);
mPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("先小涛", 400, 200, mPaint);
mPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("先小涛", 400, 300, mPaint);

setTextAlign 效果图

从效果图中可以看出,当居左对齐 (Align.LEFT) 时,整个字符串都在起始点 (400,100) 的右侧,也就是说,通过 drawText() 函数指定的起始点 (400,100) 是居左的。同样,当居右对齐 (Align.RIGHT) 时,起始点也是居右的,也就是说,所有文字都在起始点 (400,100) 的左侧。

3. 设置字体样式

1)常规设置

1
2
3
4
5
6
// 设置是否粗体。当取 true 时,表示是粗体。
void setFakeBoldText(boolean fakeBoldText)
// 是否显示文字下画线。当取 true 时,显示下画线。
void setUnderlineText(boolean underlineText)
// 是否显示中间删除线。当取 true 时,显示中间删除线。
void setStrikeThruText(boolean strikeThruText)

示例

1
2
3
4
5
canvas.drawText("先小涛 DEFAULT", 100, 200, mPaint);
mPaint.setFakeBoldText(true);
mPaint.setUnderlineText(true);
mPaint.setStrikeThruText(true);
canvas.drawText("先小涛 SETTING", 100, 300, mPaint);

字体设置效果图

2)字体倾斜度设置

1
void setTextSkewX(float skewX)

该函数用于设置字体倾斜度。参数 float skewX 的默认值是 0,取负值时文字向右倾斜,取正值时文字向左倾斜,Word 文档中倾斜字体的倾斜度是 -0.25f。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(80);
// 正常样式
canvas.drawText(mName, 100, 200, mPaint);
// 向右倾斜
mPaint.setTextSkewX(-0.25f);
canvas.drawText(mName, 100, 300, mPaint);
// 向左倾斜
mPaint.setTextSkewX(0.25f);
canvas.drawText(mName, 100, 400, mPaint);

字体倾斜度设置:正常、向右、向左

4. 水平拉伸

1
void setTextScaleX(float scaleX)

该函数用于在水平方向拉伸文字。参数 float scaleX 表示拉伸倍数,当取值为 1 时,表示不拉伸。默认为不拉伸。

示例:

1
2
3
4
5
// 正常样式
canvas.drawText(mName, 100, 200, mPaint);
// 拉伸两倍
mPaint.setTextScaleX(2f);
canvas.drawText(mName, 100, 300, mPaint);

字体水平拉伸

1.3.2 Canvas 绘制文本

1. 普通绘制

1
2
3
4
5
6
7
// 该函数可以指定起始点 (x, y) 来绘制文字
void drawText(String text, float x, float y, Paint paint)
// 通过指定字符串中字符的起始和终止位置截取字符串的一部分绘制
void drawText(String text, int start, int end, float x, float y, Paint paint)
void drawText(char[] text, int index, int count, float x, float y, Paint paint)
void drawText(CharSequence text, int start,
int end, float x, float y, Paint paint)

参数:
int start:表示起始绘制字符所在字符串中的索引。
int end:表示结束绘制字符所在字符串中的索引。
int index:指定起始绘制字符的位置。
int count:指定从起始绘制字符开始绘制几个字符。

示例:

1
canvas.drawText("先小涛后大浪", 1, 4, 100, 200, mPaint);

2. 逐个指定文字位置

1
2
void drawPosText(String text, float[] pos, Paint paint)
void drawPosText(char[] text, int index, int count, float[] pos, Paint paint)

参数:

  • char[] text/String text:要绘制的字符串。
  • int index:第一个要绘制的文字的索引。
  • int count:要绘制的文字的个数,用来计算最后一个文字的位置,从第一个绘制的文字开始算起。
  • float[] pos:要绘制的每个文字的具体位置,同样两两一组,如 {x1,y1,x2,y2,x3,y3,…}。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TestView extends View {
private Paint mPaint;
private String mName = "先小涛后大浪";
private float[] pos = {80, 180, 80, 280, 80, 380,
200, 180, 200, 280, 200, 380};
public TestView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(80);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPosText(mName, pos, mPaint);
}
}

3. 沿路径绘制

1
2
3
4
void drawTextOnPath (String text, Path path, float hOffset,
float vOffset, Paint paint)
void drawTextOnPath (char[] text, int index, int count, Path path,
float hOffset, float vOffset, Paint paint)
  • float hOffset:与路径起始点的水平偏移量。
  • float vOffset:与路径中心的垂直偏移量。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(50);
mPaint.setStyle(Paint.Style.STROKE);
mName = "先小涛后大浪";
mPath1 = new Path();
mPath1.addCircle(220, 300, 150, Path.Direction.CCW);
mPath2 = new Path();
mPath2.addCircle(600, 300, 150, Path.Direction.CCW);
// 辅助中线
canvas.drawLine(70, 300, 750, 300, mPaint);
canvas.drawPath(mPath1, mPaint);
canvas.drawPath(mPath2, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawTextOnPath(mName, mPath1, 0, 0, mPaint);
canvas.drawTextOnPath(mName, mPath2, 80, 50, mPaint);

1.3.3 设置字体样式

在 Paint 中有一个函数是专门用来设置字体样式的。

1
Typeface setTypeface(Typeface typeface)

Typeface 是专门用来设置字体样式的类,通过 paint.setTypeface() 函数来指定即将绘制的文字的字体样式。可以指定系统中的字体样式,也可以在自定义的样式文件中获取。在构建 Typeface 类时,可以指定所用样式的正常体、斜体、粗体等。如果在指定样式中没有相关文字的样式,就会用系统默认的样式来显示,一般默认是宋体。

1. 使用系统中的字体样式

1)使用 Android 自带的字体样式
在 Typeface 类中保存着三种自带的字体样式:Typeface.SANS_SERIF、Typeface.MONOSPACE 和 Typeface.SERIF。

示例:

1
2
3
4
5
6
7
8
9
// 衬线字体
mPaint.setTypeface(Typeface.SERIF);
canvas.drawText(mName, 100, 100, mPaint);
// 设置等宽字体
mPaint.setTypeface(Typeface.MONOSPACE);
canvas.drawText(mName, 100, 170, mPaint);
// 无衬线字体
mPaint.setTypeface(Typeface.SANS_SERIF);
canvas.drawText(mName, 100, 240, mPaint);

系统字体样式

由于这三种字体样式对中文的支持不是很好。所以,当遇到不支持的文字时,会使用系统默认的样式来写。对中国用户而言,系统默认的字体一般是 DroidSansFallback,所以用这三种样式的文字写中文时是看不到差别的,我们一般不会使用这三种字体样式。

2)defaultFromStyle() 函数

1
Typeface defaultFromStyle(int style)

该函数会根据字体样式获取对应的默认字体。参数 int style 的取值如下:

  • Typeface.NORMAL:正常字体。
  • Typeface.BOLD:粗体。
  • Typeface.ITALIC:斜体。
  • Typeface.BOLD_ITALIC:粗斜体。

如果系统默认的字体是宋体,那么当指定 defaultFromStyle(Typeface.BOLD_ITALIC) 时,获取的将是粗斜体的宋体样式。

示例:

1
2
3
4
5
6
7
8
9
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(50);
mPaint.setAntiAlias(true);
mName = "先小涛 xian@163.com";
Typeface typeface = Typeface.defaultFromStyle(Typeface.BOLD_ITALIC);
mPaint.setTypeface(typeface);
canvas.drawText(mName, 100, 100, mPaint);

3)create(String familyName, int style) 函数

1
Typeface create(String familyName, int style)

该函数直接通过指定字体名来加载系统中自带的字体样式。如果字体样式不存在,则会用系统样式替代并返回。

示例:

1
2
3
4
5
String familyName = "宋体";
Typeface font = Typeface.create(familyName, Typeface.NORMAL);
mPaint.setTypeface(font);
canvas.drawText(mName, 100, 100, mPaint);

2. 自定义字体样式

一般而言,我们不会指定系统自带的字体样式。因为除 Android 自带的三种字体样式以外,其他字体样式并不一定在每款手机上都有预装。所以,我们一般会选择加载自定义的字体文件来绘制文字,这样才不至于在每款手机上的表现不一样。

如果要自定义字体样式,就需要从外部字体文件中加载我们所需的字形,这时所使用的 Typeface 构造函数有如下三个:

1
2
3
Typeface createFromAsset(AssetManager mgr, String path)
Typeface createFromFile(String path)
Typeface createFromFile(File path)

示例:

1
2
3
4
5
6
AssetManager manager = context.getAssets();
// 加载字体文件:assets/fonts/xian.ttf
Typeface typeface = Typeface.createFromAsset(manager, "fonts/xian.ttf");
mPaint.setTypeface(typeface);
canvas.drawText(mName, 100, 200, mPaint);

加载 res/font/xian.ttf 字体文件方式:
Typeface typeface = ResourcesCompat.getFont(context, R.font.xian);