理论

Android字体属性Paint.FontMetrics

2020-01-09  本文已影响0人  dlihasa

前言

最近在做需求的时候需要一个日历控件,在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。

上一篇下一篇

猜你喜欢

热点阅读