android drawText()方法中x,y坐标值真正的 意义

我们在绘制文字的时候是通过canvas的drawText(String text, float x, float y,Paint paint)方法第一个和第四个参数都知道,但是x,y知道传的是什么坐标么,其实传的是基线值,因为在绘制文字的时候有几个值要了解下:

android drawText()方法中x,y坐标值真正的 意义_第1张图片

是不是有点像学音乐的线谱,现在简单说明下

top,bottom是文字绘制的时候绝对不能超过的,也就是高不能超过top,底部不能超过bottom.

asent,descent是系统建议不要超过的,但是有时候绘制文字会超过,比如你绘制一个g字母下面可能就会 超过descent

而x,y就是指baseline(基线)为准的值,我们在这画一个坐标:

android drawText()方法中x,y坐标值真正的 意义_第2张图片

通过上面的坐标我们知道top和ascent是负值 而bottom和descent是正值

从上面的坐标我们可以得到如下几个等式:

top = top线的y坐标 - baseline线的y坐标
bottom = bottom线的y坐标 - baseline线的y坐标
ascent = ascent线的y坐标 - baseline线的y坐标
desent = desent线的y坐标 - baseline线的y坐标

在android中top bottom ascent descent其实已经封装成类了在Paint内部类有一个:

public static class FontMetrics {
    /**
     * The maximum distance above the baseline for the tallest glyph in
     * the font at a given text size.
     */
    public float   top;
    /**
     * The recommended distance above the baseline for singled spaced text.
     */
    public float   ascent;
    /**
     * The recommended distance below the baseline for singled spaced text.
     */
    public float   descent;
    /**
     * The maximum distance below the baseline for the lowest glyph in
     * the font at a given text size.
     */
    public float   bottom;
    /**
     * The recommended additional space to add between lines of text.
     */
    public float   leading;
}
leading指的是行间距

通过FontMetrics转化下:

      bottom = baseline + FontMetrics.bottom
top = baseline + FontMetrics.top

而我们是要求y坐标的值,如下图:

android drawText()方法中x,y坐标值真正的 意义_第3张图片

文字中心其实就是view的高度一半,这是个已知值,我们只要求出C的坐标然后加上啊+view高度的一半就是y的值,

图中A和B的值是相等的

A=B = (bottom - top)/2 这里A和B指的是长度

而    bottom = baseline + FontMetrics.bottom
top = baseline +FontMetrics.top

所以A=B = FontMetrics.bottom/2-FontMetrics.top/2,而C=B-bottom的值也就是 FontMetrics.bottom/2-FontMetrics.top/2-(baseline + FontMetrics.bottom)

而C又等于baseline-center  所以是baseline-center = B-(bottom-baseline)也就是baseline-center = B-(baseline+FontMetrics.bottom-baseline)结果是:

baseline-center = FontMetrics.bottom/2-FontMetrics.top/2-FontMetrics.bottom

而center=view.getHeight/2所以baseline=FontMetrics.bottom/2-FontMetrics.top/2-FontMetrics.bottom+view.getHeight/2;

也就是y的值是FontMetrics.bottom/2-FontMetrics.top/2-FontMetrics.bottom+view.getHeight/2;最终优化下算法是

y=-(FontMetrics.bottom+FontMetrics.top)/2+view.getHeight/2


这个如果在一个圆中绘制文字,如果计算不对的话也就是不在中心点很容易看的出来,现在就写一个简单的demo,自定义一个CircleProgressView

代码如下:

package com.example.circleprogressview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by zhouguizhi on 2017/8/27.
 */
public class CircleProgressView extends View {
    private int max = 100;
    private Paint paint;
    private float progress = 0;
    private int roundColor =Color.parseColor("#008080");
    private int textColor = Color.parseColor("#696969");
    private int roundProgressColor = Color.parseColor("#DEB887");
    private float textSize = 40;
    private float roundWidth = 24;
    private int percent = 0;

    public CircleProgressView(Context context) {
        this(context,null);
    }
    public CircleProgressView(Context context,  AttributeSet attrs) {
        this(context, attrs,0);
    }
    public CircleProgressView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }
    private void initPaint() {
        paint = new Paint();
        paint.setColor(roundColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(roundWidth);
        paint.setAntiAlias(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawCircle(canvas);
        drawText(canvas);
        drawOval(canvas);
        postDelayed(new Runnable() {
            @Override
            public void run() {
                progress += 1;
                if(progress>100){
                    return;
                }
                postInvalidate();
            }
        },100);
    }
    private void drawOval(Canvas canvas) {
        if(null!=canvas){
            RectF oval = new RectF(roundWidth/2, roundWidth/2, getWidth()-roundWidth/2, getWidth()-roundWidth/2);
            paint.setColor(roundProgressColor);
            paint.setStrokeWidth(roundWidth);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeCap(Paint.Cap.ROUND);
            canvas.drawArc(oval, 0 , 360 * progress / max, false, paint);
        }
    }
    private void drawText(Canvas canvas) {
        if(null!=canvas){
            paint.setColor(textColor);
            paint.setStrokeWidth(0);
            paint.setTextSize(textSize);
            percent = (int)(progress / (float)max * 100);
            String strPercent = percent + "%";
            Paint.FontMetricsInt fm = paint.getFontMetricsInt();
            if(percent != 0){
                canvas.drawText(strPercent, getWidth() / 2 - paint.measureText(strPercent) / 2 ,
                        getHeight() / 2-(fm.bottom+fm.top)/2, paint);
            }
        }
    }
    private void drawCircle(Canvas canvas) {
        if(null!=canvas){
            float radius = getWidth() / 2 - roundWidth/2;
            paint.setStrokeWidth(24);
            canvas.drawCircle(getWidth() / 2,getWidth() / 2,radius,paint);
            paint.setColor(roundColor);
            canvas.drawCircle(getWidth() / 2,getWidth() / 2,radius,paint);
        }
    }
}
这个代码简单,没啥可解释的,看效果:

android drawText()方法中x,y坐标值真正的 意义_第4张图片

你可能感兴趣的:(android drawText()方法中x,y坐标值真正的 意义)