一. 前言

画笔的设置会影响到文字的绘制。所以,我们需要先了解自定义View-Paint

绘制文本有三类方法:

其中drawText()最常用,drawPosText ()是根据一个个坐标点指定文字位置,drawTextOnPath ()是根据路径绘制。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 第一类
public void drawText (String text, float x, float y, Paint paint)
public void drawText (String text, int start, int end, float x, float y, Paint paint)
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
public void drawText (char[] text, int index, int count, float x, float y, Paint paint)

// 第二类
public void drawPosText (String text, float[] pos, Paint paint)
public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)

// 第三类
public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
public void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)

二. drawText

1
public void drawText (String text, float x, float y, Paint paint)

很明显,这里的 x 和 y 是用来确定文本的绘制位置的。但是,这个点是绘制文本的那里,我们还是不清楚。

1. 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Paint paint=new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(12);
paint.setTextSize(100);

String text="测试:my text";
canvas.drawText(text, 200, 400, paint);

//画两条线标记位置
paint.setStrokeWidth(4);
paint.setColor(Color.RED);
canvas.drawLine(0, 400, 2000, 400, paint);
paint.setColor(Color.BLUE);
canvas.drawLine(200, 0, 200, 2000, paint);

x的值默认是文字的左边界,通过setTextAlign()指定,默认为left。

setTextAlign()指定为center,此时x的值是文字的中心位置。

setTextAlign()指定为right,此时x的值是文字的右边界。

这里,我们就很清楚的知道了Paint的setTextAlign方法的作用以及drawText方法中x值的作用。

drawText方法中y值我们猜测应该是文字的下边界,但是通过测试发现,y值比文字的下边界高。

2. 文字的基线

透过这张图的字符y以及对比上面图中的字母y我们可以发现,y的值是Baseline,也就是文字的基线。

那么,这些值如何获取呢?

1
2
3
4
5
Paint.FontMetrics fontMetrics=paint.getFontMetrics();
fontMetrics.top
fontMetrics.ascent
fontMetrics.descent
fontMetrics.bottom

记得要在设置完Paint的文字大小,宽度之类属性后再获取FontMetrics,baseline对应对应值为0,在它下面的descent和bottom值为正,top和ascent为负。那文字的高度为bottom - top

3. 文字居中方案

① y = 矩形中心y值 + 矩形中心与基线的距离

② 矩形中心与基线的距离 = 文字高度的一半 - 基线到文字底部的距离(也就是bottom)

1
(fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom

三. demo

1. MyTextView类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class MyTextView extends View {
private Paint paint;

public MyTextView(Context context) {
super(context);

init();
}

public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);

init();
}

private void init(){
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(40);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//绘制的文本
String message = "Hello,you!";

//计算文本的宽度,高度
float textWidth = paint.measureText(message);
float textHeight = paint.getFontMetrics().bottom-paint.getFontMetrics().top;

//计算Baseline和中心线的距离
float distance = textHeight / 2 - paint.getFontMetrics().bottom;

//计算绘制的x点
float x = (getWidth() - textWidth) / 2;

//计算绘制的y点
float y = (getHeight() - textHeight) / 2 + textHeight / 2 + distance;

//绘制文本
canvas.drawText(
"Hello,you!",
x, y, paint
);
}
}

2. 布局文件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<swu.xl.drawtext.MyTextView
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:background="@color/colorAccent"
/>

</RelativeLayout>

3. 运行效果

参考文章

Android Canvas的drawText()和文字居中方案

android高级自定义View之Paint高级使用(文字绘制)