Android中绘制一个View都不陌生,例如一个TextView我们在onDraw方法中新建一个Paint对象就ok了,drawText就行了,但是它的高度怎么理解,记录一下,看下图:
这个图是Android绘制文字的一个标准,中间红色实线是baseline,就是一个基准线,是不是很像我们英语作业本的线条~~ 包括小写的英文字母j下面的勾也是伸出了那个基准线,这个线就是我们canvas.drawText方法中的第三个参数y值,所以当我们这样调用API方法canvas.drawText("Jj",0,0,paint) 的时候 我们会发现页面上什么也没有,为什么?因为第三个参数为0,所以你的文字绘制到了屏幕外面去了,看不到了。
接下来说说图片中的四个参数:
public static class FontMetrics {
public float ascent;
public float bottom;
public float descent;
public float leading;
public float top;
public FontMetrics() {
throw new RuntimeException("Stub!");
}
}
这个类就是我们获取绘制的文字的高度的时候要用到的
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
结合上面的图片理解一下:
ascent; 距离基准线的往上的一个正常距离 是一个负数值
descent; 距离基准线的往下的一个正常距离 是一个正数值
什么叫正常距离,就是说一般的文字 它的高度基本都在ascent - descent这样的一个高度 不排除其他文字比如藏文,有可能会超出ascent和descent,这个时候就有了下面的俩参数:
bottom; 距离基准线的往下的最大距离 是一个正值
top; 距离基准线的往的上最大高度 是一个负值 就是说无论什么文字 最大的高度都不会高于bottom - top的高度
所以延伸出一下问题,如果我们的text想要绘制在屏幕的正中间该怎么办?基准线要调整为 getHeight()/2 + (ascent - descent)/2 - descent 为什么又减去了descent,因为基准线并不是在文字的最底部,而是距离文字最底部往上descent的一个高度。
得出的结果就是 getHeight()/2 - (ascent + descent)/2 就是基准线在Y轴上的位置,X轴上位于中间并且设置文字剧中就ok了
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text,getWidth()/2,getHeight()/2 - (fontMetrics.ascent + fontMetrics.descent)/2,paint);
实现一个简单的例子:
package com.example.textdraw;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
/**
* 自定义view
*/
public class ColorTextView extends AppCompatTextView {
String text = "ABGgHIJj你好";
public ColorTextView(@NonNull @org.jetbrains.annotations.NotNull Context context) {
super(context);
}
public ColorTextView(@NonNull @org.jetbrains.annotations.NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) {
super(context, attrs);
}
public ColorTextView(@NonNull @org.jetbrains.annotations.NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
drawLineX(canvas);
paint.setTextSize(80);
//文字绘制的一个基准线 因此这个值不能为0,最小要高于文字的高度,否则文字就会显示不出来或者显示不全
float baseLine = 100;
float x = getWidth()/2;
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text,x,baseLine,paint);
// LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getWidth(),getHeight());
// setLayoutParams(layoutParams);
// canvas.drawText(text,x,getHeight()/2,paint);
drawCenterText(canvas,paint);
}
private void drawLineX(Canvas canvas){
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
canvas.drawLine(0,100,getWidth(),100,paint);
paint.setColor(Color.RED);
canvas.drawLine(getWidth()/2,0,getWidth()/2,getHeight(),paint);
canvas.drawLine(0,getHeight()/2,getWidth(),getHeight()/2,paint);
}
/**
* 测量文字的宽高
*/
private void drawCenterText(Canvas canvas,Paint paint){
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
//FontMetrics 里面有四个参数
// public float ascent; 距离基准线的往上的一个正常距离
// public float descent; 距离基准线的往下的一个正常距离 就是说一般的文字 它的高度基本都在ascent - descent这样的一个高度
// public float leading;
// public float bottom; 距离基准线的往下的最大距离 是一个正值
// public float top; 距离基准线的往的上最大高度 是一个负值 就是说无论什么文字 最大的高度都不会高于bottom - top的高度
// 所以为了能让文字绘制在屏幕正中间 我们基准线应该是 getHeight()/2 + (ascent - descent)/2 - descent 为什么又减去了descent,因为基准线并不是文字的最底部,而是距离文字最底部往上descent的一个高度
//得出的结果就是 getHeight()/2 - (ascent + descent)/2 就是基准线在Y轴上的位置
canvas.drawText(text,getWidth()/2,getHeight()/2 - (fontMetrics.ascent + fontMetrics.descent)/2,paint);
// float width = paint.measureText(text); 测量文字的宽度 可以测试每一个文字占用的宽度累加来判断是否需要换行
}
}
运行的效果如下:蓝色线条为基准线,红色的是X和Y上的中线