我们在绘制文字的时候是通过canvas的drawText(String text, float x, float y,Paint paint)方法第一个和第四个参数都知道,但是x,y知道传的是什么坐标么,其实传的是基线值,因为在绘制文字的时候有几个值要了解下:
是不是有点像学音乐的线谱,现在简单说明下
top,bottom是文字绘制的时候绝对不能超过的,也就是高不能超过top,底部不能超过bottom.
asent,descent是系统建议不要超过的,但是有时候绘制文字会超过,比如你绘制一个g字母下面可能就会 超过descent
而x,y就是指baseline(基线)为准的值,我们在这画一个坐标:
通过上面的坐标我们知道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坐标的值,如下图:
文字中心其实就是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); } } }这个代码简单,没啥可解释的,看效果: