首页 > 学院 > 开发设计 > 正文

Canvas使用 -- 在canvas上绘制圆角矩形并添加文字

2019-11-09 18:20:48
字体:
来源:转载
供稿:网友

前言

先来闲聊一下写这个题目的原因吧,其实这个知识点对于大神来说其实是很简单的,所以如果大神看到这里的话,其实就可以不用看下去了。至于如果是新手,或者说跟本人一样,对于canvas的操作还有疑惑的朋友,希望你可以从这篇文章中得到你想要的答案,同时可以解决你的问题。 其实这个文章源自于最近项目需要重构,不得不说,作为一个迈过十年时光的项目来说,要进行重构还是比较烦恼的,至于这个烦恼的原因吧,不用多说,大家也应该知道在产品X闲着没事,正在为自己的KPI而担心的时候,总想搞点事情,这也是无可厚非,尤其是一个菜鸟产品X急切需要表现的时候。当然了,话虽这么说,但是能够为这个有十年光景的项目进行一次重构,心里还是有点小激动的,毕竟能够吸收前人的思想,同时自己又可以在项目中大展身手,对自己来说也是好的。 那么我就来说说这个需求吧,因为我们应用是小说阅读器,所以自然阅读页上面肯定是重中之重,而这一块在性能上的要求无疑也是比较高的,如果单纯使用各种View的组合成为一个新的View,明显这样也是可以的,但是这样的性能必然不是很好,因为这里涉及到多层View的嵌套操作,同时对视图的过度渲染也会导致卡慢等的情况出现,所以最好的方式我们最好还是通过在canvas进行操作了。当然这里我给出的只是canvas操作中的一个我遇到问题时的操作,这些问题可能在大牛看来不值一提,但是哪个敢说未来的大牛不会踩一下坑呢?所以我就只能给自己这样的小白归纳一下自己的问题了,当然由于是重构项目,后续肯定还会有各种各样的问题,所以如果有兴趣的朋友可以关注我的博客,后续我会将我重构中的问题一一收集。

正文

首先我们先来看看canvas的一些基本的常用的操作

操作类型 相关API 备注
绘制颜色 drawColordrawRGBdrawARGB 使用单一颜色填充canvas
绘制基本形状 drawPointdrawPointsdrawLinedrawLinesdrawRectdrawRoundRectdrawOval,drawCircle,drawArc 依次是点、线、矩形、圆角矩形椭圆、圆、圆弧
绘制图片 drawBitmap,drawPicture 绘制位图和图片
绘制文本 drawText,drawPostTextdrawTextOnPath 依次是绘制文字、绘制文字时根据制定每个文字位置、根据路径绘制文字
绘制路径 drawPath 绘制路径,绘制贝塞尔曲线时也需要用到该函数
顶点操作 drawVerticesdrawBitmapMesh 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、drawBitmapMesh只对绘制的bitmap作用
画布裁剪 clipPath,cliPRect 设置画布的显示区域
画布快照 save,restore,saveLayerXxx,restoreToCount,getSaveCount 依次是保存当前状态、回滚到上一次保存的状态、保存图层状态、回滚到制定状态、获取保存次数
画布变换 translate,scale,rotate,skew 依次是位移、缩放、旋转、错切
Matrix矩阵 getMatrix,setMatrix,concat 实际上画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解故封装了一些常用的方法

当然这么多的操作,其实都只是列举,实际上这篇文章中,我们用到的仅仅只是drawRoundRect以及drawText而已,其他的操作可以在网上查找更多的资料自行了解,当然也可以继续关注我的后续文章。

NeoBosco 上图是我们想要实现的结果,当然看到这个图的时候,肯定很多人会觉得这样做其实很简单,不就是绘制一个圆角的矩形,然后通过计算坐标的方式,将文本绘制到矩形的居中位置就好了。好吧,我承认我当时也就是这么想的,但是在我这么甘的时候问题就来了。

使用drawRoundRect()和drawText()绘制时总会出现莫名其妙的偏差

float startX = 100 ;float startY = 100 ;float endX = 600 ;float endY = 200 ;RectF rectF = new RectF(startX, startY, endX, endY);canvas.drawRoundRect(rectF, 20, 20, mButtonPaint);

首先我们通过上面代码在canvas上绘制出一个圆角的矩形。说到这里就要提一句,canvas.drawRoundRect()有两个不同参的函数,因为博主的项目中需要兼容较低的android系统版本,所以采用上面比较通用的绘制圆角矩形的API。当然这里可能还有一些读者会问Rect和RectF的区别,这个其实度娘一下就已经有很多答案了,博主就不详述了,它代表了坐标系内某一块矩形区域的参数封装,而Rect跟RectF区别在于得到的值的精度问题以及部分API的不同。

String text = "购买本章" ;Paint.FontMetrics fontMetrics = mButtonTextPaint.getFontMetrics();canvas.drawText(text, (endX - startX) / 2 + startX , (fontMetrics.bottom - fontMetrics.top) / 2 + startY , mButtonTextPaint);

接着通过上面的代码,在圆角矩形的居中的位置绘制文本,这里的计算比较简单,就是通过画笔Paint.FontMetrics对文本进行计算。 绘制的文本的X坐标 = (结束的X坐标 - 起始的X 坐标) / 2 + 起始坐标。 绘制文本的Y坐标 = (文本的bottom坐标 - 文本的top坐标) / 2 + 起始的Y坐标。

NeoBosco

本来以为万无一失的情况,却想不到来了一记晴天霹雳,这蛋疼的位置是什么鬼情况。。。。 当然面对这样的一种情况,还不至于让我们觉得蛋疼,毕竟调这东西改改算式就好了,慢慢调就好,然!而!事情并没有那么简单,我一开始认为是计算的问题,而后有认为会不会是drawRoundRectdrawText是不是使用的坐标不是同一个,为何出现了这样的偏差呢??但是想想,虽然我大天朝不能用 Google ,但是也不至于这么蛋疼整我们这些小资程序员吧,所以就想了个测试的方法,就是将文本跟的起始坐标跟圆角矩形的起始坐标设置成一样,这样不就能排除问题了吗?

String text = "购买本章" ;Paint.FontMetrics fontMetrics = mButtonTextPaint.getFontMetrics();canvas.drawText(text, startX, startY, mButtonTextPaint);

然后就将绘制文本的代码的X,Y坐标改成跟RoundRect的X,Y坐标一致。 然!而! NeoBosco

WTF~~这是什么鬼。。为什么即使设置成一样的X,Y坐标却相差那么远,这不是瞎搞吗?来到这个地步,难道还敢说这坑爹的不是两种不同的坐标系? 然!而!峰回路转的是,这还真不是两个坐标系不同,这里面还有一个坑爹的知识点,就是baseline的概念,什么是baseline?就是所谓的基线了,至于概念这里就长篇大论了,这个在度娘上面,你找到的解释简直是多如繁星。接着,我们知道问题可能在文本的baseline上面的话,我们就可以尝试一下这个问题了。

Paint.FontMetrics fontMetrics = mButtonTextPaint.getFontMetrics();float baseline = (rectF.bottom + rectF.top - fontMetrics.bottom - fontMetrics.top) / 2;canvas.drawText(text, rectF.centerX(), baseline, mButtonTextPaint);

所以这里我就将baseline进行重新计算,然后再一次绘制文本。。

NeoBosco

我们惊讶的发现,问题就这么容易就被解决了,而这算式在度娘上也是能够找到,所以也就不解释了,到此本文所说的问题也就解决了,希望能够帮到大家,谢谢!


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表