前言
最近在做需求的时候需要一个日历控件,在github上看CalendarView不错,UI部分完全可以由使用者来自定义绘制,绘制过程中遇到了Paint.FontMetrics,梳理一下。
概念
FontMetrics 字体度量,该类是Paint的内部类,通过getFontMetrics()方法可获取字体相关属性。
字体的几个属性
baseline Android文本绘制是以baseline为基准的
ascent baseline之上至字符最高处的距离,以baseline为基准,负值
descent baseline之下至字符最低处的距离,以baseline为基准,正值
leading 上一行文字的descent到当前行文字的ascent称为行距
top 最高字符到baseline的值,以baseline为基准,负值
bottom 最下字符到baseline的值,以baseline为基准,正值
从网上找了张图,直观看下:
注:好多文章说top和bottom分别是ascent和descent的最大值,但是我理解不了,我看到各种标注和我的demo示例表现,ascent和descent未达到过top和bottom的值,可能是说这两个值不可能超过top和bottom吧
分别来看我代码在两个机型上运行出来的示例值:
2020-01-09 14:23:00.031 17100-17100/com.dhasa.drawabletintdemo D/font: leading:0.0
2020-01-09 14:23:00.031 17100-17100/com.dhasa.drawabletintdemo D/font: ascent:-74.21875
2020-01-09 14:23:00.031 17100-17100/com.dhasa.drawabletintdemo D/font: descent:19.53125
2020-01-09 14:23:00.031 17100-17100/com.dhasa.drawabletintdemo D/font: top:-84.49219
2020-01-09 14:23:00.031 17100-17100/com.dhasa.drawabletintdemo D/font: bottom:21.679688
01-09 14:26:35.799 10045-10045/com.dhasa.drawabletintdemo D/font: leading:0.0
01-09 14:26:35.799 10045-10045/com.dhasa.drawabletintdemo D/font: ascent:-69.0625
01-09 14:26:35.799 10045-10045/com.dhasa.drawabletintdemo D/font: descent:19.0625
01-09 14:26:35.799 10045-10045/com.dhasa.drawabletintdemo D/font: top:-69.0625
01-09 14:26:35.799 10045-10045/com.dhasa.drawabletintdemo D/font: bottom:19.0625
很巧,同一份代码,下边这个机型的这组数据数值竟然是相等的,但是一般是不相等的。
应用代码示例
文字居中的实例
public class CenterFontView extends View {
private Paint paint;
private Rect targetRect;
private String testString = "测试:LoveJjh2020";
public CenterFontView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(3);
paint.setColor(Color.RED);
paint.setTextSize(80f);
targetRect = new Rect(50,50,1000,200);
}
public CenterFontView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CenterFontView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.RED);
canvas.drawRect(targetRect,paint);
paint.setColor(Color.GREEN);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
Log.d("font", "leading:" + fontMetrics.leading);
Log.d("font", "ascent:" + fontMetrics.ascent);
Log.d("font", "descent:" + fontMetrics.descent);
Log.d("font", "top:" + fontMetrics.top);
Log.d("font", "bottom:" + fontMetrics.bottom);
// float baseline = targetRect.top + (targetRect.bottom - targetRect.top)/2f - (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.top;
float baseline = targetRect.top + (targetRect.bottom - targetRect.top)/2f + (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom;
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(testString,targetRect.centerX(),baseline,paint);
}
}
实现效果:
红配绿真香~
值得说明一点的是计算文字baseline的过程,两种写法:
float baseline = targetRect.top + (targetRect.bottom - targetRect.top)/2f
- (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.top;
float baseline = targetRect.top + (targetRect.bottom - targetRect.top)/2f
+ (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom;
要将文字垂直居中,首先找到文字所在控件的竖直方向的中点,然后加上或者减去文字高度的一半,就是文字需要展示位置的底部或者顶部,在根据baseline和底部或者顶部的差值(fontMetrics.bottom/fontMetrics.top)计算得出画文字的baseline。
网友评论