canvas.drawText理解和FontMetrics文字测量

在ui开发开发中,label文本标签是最长用到的 。中提供了帮我们用来展示文本文字 。而的也提供了用于帮助我们在自定义view的时候绘制展示文本 。
先简单看一下这段代码
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)init {paint.textSize = 150Fpaint.style = Paint.Style.FILL_AND_STROKEpaint.color = Color.parseColor("#FFFFFF")}override fun onDraw(canvas: Canvas?) {super.onDraw(canvas)canvas?.drawColor(Color.parseColor("#80F14400"))val textLabel = "Hello World, Hello Python"canvas?.drawText(textLabel, 0F, 0F, paint)}
上面这段代码,是一个最简单的使用 。按照我们对坐标系的理解,貌似没什么问题,应该是在view的左上角绘制文本,文本完整展示 。
从真实的展示上效果来看,和我们想要的效果完全不一致,为什么会出现这种情况呢?还是看一下的方法定义吧 。
从方法的注释中可以得知的x和y分别是用来定义文字绘制的起始点,而这个起始点的y坐标是基于(基线) 。想要理解的概念,就要理解文字的测量规则,文字测量规则是使用方法中定义的 。而是从Paint.()获取 。
在看定义之前,先看一下这张图,这张图是从别人博客copy过来的(对于图片中的值,图中理解不是很正确,暂时忽略)
指的是行的额外间距,即对于上下相邻的两行,上行的线和下行的 top 线的距离
类主要是定义了文字的测量属性 。
public static class FontMetrics {/*** The maximum distance above the baseline for the tallest glyph in* the font at a given text size.* 在给定的文本大小下,字体中最高字形的基线上方的最大距离 。*/public floattop;/*** The recommended distance above the baseline for singled spaced text.* 对于单行分隔的文本,建议的基线上方距离 。*/public floatascent;/*** The recommended distance below the baseline for singled spaced text.* 推荐的基线以下距离,用于分隔的文本 。*/public floatdescent;/*** The maximum distance below the baseline for the lowest glyph in* the font at a given text size.* 在给定的文本大小下,字体下方最低字形的基线以下最大距离 。*/public floatbottom;/*** The recommended additional space to add between lines of text.* 建议在文本行之间添加额外的空格 。*/public floatleading;}
从上面的定义中以及中可以发现,都是使用作为一个基准线来确定距离 。
可以看出来的确认很重要,那么接下来看一下怎么计算 。
从图中可以看出来,的大小y值等于. +-. 。那么,可以打印一下的各个属性的值,看一下输出 。
val fontMetrics = paint.fontMetricsLog.e("info", "fontMetrics-->top: " + fontMetrics.top)Log.e("info", "fontMetrics-->leading: " + fontMetrics.leading)Log.e("info", "fontMetrics-->ascent: " + fontMetrics.ascent)Log.e("info", "fontMetrics-->descent: " + fontMetrics.descent)Log.e("info", "fontMetrics-->bottom: " + fontMetrics.bottom)
E/info: –>top: -157.2
E/info: –>: 0.0
E/info: –>: -139.2
E/info: –>: 36.
E/info: –>: 40.65
将打印的结果对照图,会发现,起始数据基于,在上方的为负数、下方的为正数 。
知道了怎么每个值的意义和的计算方式之后,我们就可以根据作为绘制出来每个属性的辅助线和文字
【canvas.drawText理解和FontMetrics文字测量】val fontMetrics = paint.fontMetricsval baseline = fontMetrics.bottom + kotlin.math.abs(fontMetrics.top) - fontMetrics.descentcanvas?.save()//将坐标零点y值移动到baselinecanvas?.translate(0F,baseline)paint.color = Color.BLUEval textLabel = "Hello,Python"canvas?.drawText(textLabel, 0F, 0F, paint)paint.style = Paint.Style.STROKE//绘制toppaint.color = Color.BLUEcanvas?.drawLine(0F, fontMetrics.top, width.toFloat(), fontMetrics.top, paint)paint.color = Color.YELLOW//绘制ascentcanvas?.drawLine(0F, fontMetrics.ascent, width.toFloat(), fontMetrics.ascent, paint)paint.color = Color.GRAY//绘制descentcanvas?.drawLine(0F, fontMetrics.descent, width.toFloat(), fontMetrics.descent, paint)paint.color = Color.parseColor("#F15500")//绘制bottomcanvas?.drawLine(0F, fontMetrics.bottom, width.toFloat(), fontMetrics.bottom, paint)//绘制baselinepaint.color = Color.parseColor("#8080FF")paint.pathEffect = DashPathEffect(floatArrayOf(10F, 10F), 0F)canvas?.drawLine(0F, 0F, width.toFloat(), 0F, paint)canvas?.restore()