Paint的基本使用

2020-12-14  本文已影响0人  code希必地

1、文字的绘制

1.1、四线格与基线

先看下文字在四线格中的展示


image.png

在Canvas中绘制文字也是有规则的,这个规则就是基线,下面看下什么是基线


image.png
从上图可见,只要基线确定了,那么文字的位置就确定。

1.2、drawText()与基线的关系

public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)

上面函数是常用的绘制文字的方法,其中(x,y)并不是绘制文字的左上角点,而是基线开始处的位置,如下图小点的位置就是点(x,y)


image.png

可见:

1.3、绘图四线格和FontMetrics

1.3.1、文字的绘图四线格

除了基线之前,绘制文字还有4条线:ascent、descent、top和bottom,如下图所示


image.png

1.3.2、FontMetrics

上面所提到的ascent、descent、top、bottom是如何计算的呢?系统提供了FontMetrics,它里面有4个成员变量:

public float ascent;
public float bottom;
public float descent;
public float leading;
public float top;

它们的计算方式和含义如下:

override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)
    paint.setColor(Color.RED)
    paint.textSize=120f

    canvas?.drawText("harvic \\’ s blog", baselinex, baselineY, paint)

    val fontMetrics = paint.getFontMetrics()
    val ascentY = fontMetrics.ascent + baselineY
    val dsecentY = fontMetrics.descent + baselineY
    val topY = fontMetrics.top + baselineY
    val bottomY = fontMetrics.bottom + baselineY
    val mWidth = width.toFloat()
    val lineArray = floatArrayOf(
        baselinex, ascentY, mWidth, ascentY,
        baselinex, baselineY, mWidth, baselineY,
        baselinex, dsecentY, mWidth, dsecentY,
        baselinex, topY, mWidth, topY,
        baselinex, bottomY, mWidth, bottomY
    )
    canvas?.drawLines(lineArray,paint)
}

效果图如下


image.png

1.4、常见函数

下面讲解下如何获取文字所占的宽度、高度以及最小矩形


image.png

灰色部分就是文字所占的宽度和高度,黑色部分就是所占的最小矩形。

1.4.1、高度

字符串所占的高度很容易计算,直接用bottom线所在的y坐标减去top线坐在的y坐标即可。

val fontMetrics = paint.getFontMetrics()
val bottom=baselineY+fontMetrics.bottom
val top=baselineY+fontMetrics.top
val height=bottom-top

1.4.2、宽度

宽度也非常容易得到,利用下面函数即可

public float measureText(String text)

示例如下

 paint.textSize = 120f
val width = paint.measureText("harvic \\’ s blog")

1.4.3、最小矩形

最小矩形也是通过系统函数获取的,函数及其意义如下:

public void getTextBounds(String text, int start, int end, Rect bounds)

这个函数的作用是获取指定字符串的最小矩形,以(0,0)所在位置为基线

canvas?.drawText(str, 0f, 200f, paint)

paint.getTextBounds(str, 0, str.length, dstRect)
Log.e(javaClass.simpleName,"${dstRect.toShortString()}")
paint.style = Paint.Style.STROKE
paint.setColor(Color.BLACK)
canvas?.drawRect(dstRect, paint)

打印log如下:

PaintView: [8,-90][547,26]

发现最小矩形左上角的点的y坐标为负值,这是因为getTextBounds()获取的最小矩形是以(0,0)所在位置为基线,所以为负值。
看下面的原理图


image.png

从图中可知,只需要向下平移baselineY的距离即可,修改上面的代码即可正确的绘制出矩形实际的位置

canvas?.drawText(str, 0f, 200f, paint)
//增加平移代码
canvas?.translate(0f,200f)
paint.getTextBounds(str, 0, str.length, dstRect)
Log.e(javaClass.simpleName,"${dstRect.toShortString()}")
paint.style = Paint.Style.STROKE
paint.setColor(Color.BLACK)
canvas?.drawRect(dstRect, paint)

效果图如下


image.png

1.5、示例

1.5.1、给定左上角点绘图

假定给出所有绘制文字的左上角点,然后画出文字,先来看一张图片


image.png

图中红色点就为给出的点,我们可以利用这个点,计算出基线的y坐标baselineY。
上面学习了FontMetrics,可得到一个公式

val fontMetrics = paint.getFontMetrics()
fontMetrics.top = mTop - baseLineY

所以基线的Y坐标为

val baseLineY = mTop - fontMetrics.top

最终代码如下

//画top线
canvas?.drawLine(0f,mTop,width.toFloat(),mTop,paint)

val fontMetrics = paint.getFontMetrics()
val baseLineY = mTop - fontMetrics.top

//画基线
canvas?.drawLine(0f,baseLineY,width.toFloat(),baseLineY,paint)

//绘制文字
canvas?.drawText(str, 0f, baseLineY, paint)

1.5.2、给定中间线绘制文字

加上文字所在矩形的中间线,目前存在下面几条线,如下图:


image.png

从上图进行推导baseline的y坐标,过程如下:

A=C=(bottom.y-top.y)/2 即A=C=(FontMetrics.bottom-FontMetrics.top)/2
C=(bottom.y-baseline.y)+B 即C=FontMetrics.bottom+B
B=baseline.y-center.y 
则C=FontMetrics.bottom+baseline.y-center.y 
即(FontMetrics.bottom-FontMetrics.top)/2=FontMetrics.bottom+baseline.y-center.y 
则baseline.y=(-FontMetrics.top-FontMetrics.bottom)/2+center.y

计算出baseline.y之后就可以计算出top.bottom了

val top = fontMetrics.top + baselineY
val bottom=fontMetrics.bottom+baselineY

具体代码如下:

val fontMetrics = paint.getFontMetrics()
//画基线
val baselineY = (-fontMetrics.top - fontMetrics.bottom) / 2 + mCenter
canvas?.drawLine(0f, baselineY, width.toFloat(), baselineY, paint)
//画top线
val mTop = fontMetrics.top + baselineY
canvas?.drawLine(0f, mTop, width.toFloat(), mTop, paint)
//画center
canvas?.drawLine(0f, mCenter, width.toFloat(), mCenter, paint)
//画bottom
val mBottom = fontMetrics.bottom + baselineY
canvas?.drawLine(0f, mBottom, width.toFloat(), mBottom, paint)
//画文字
canvas?.drawText(str, 0f, baselineY, paint)

效果如下


image.png

2、Paint常用函数

上一篇 下一篇

猜你喜欢

热点阅读