您的位置:首页 > 移动开发 > Android开发

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

2017-02-07 01:58 435 查看

前言

先来闲聊一下写这个题目的原因吧,其实这个知识点对于大神来说其实是很简单的,所以如果大神看到这里的话,其实就可以不用看下去了。至于如果是新手,或者说跟本人一样,对于canvas的操作还有疑惑的朋友,希望你可以从这篇文章中得到你想要的答案,同时可以解决你的问题。

其实这个文章源自于最近项目需要重构,不得不说,作为一个迈过十年时光的项目来说,要进行重构还是比较烦恼的,至于这个烦恼的原因吧,不用多说,大家也应该知道在产品X闲着没事,正在为自己的KPI而担心的时候,总想搞点事情,这也是无可厚非,尤其是一个菜鸟产品X急切需要表现的时候。当然了,话虽这么说,但是能够为这个有十年光景的项目进行一次重构,心里还是有点小激动的,毕竟能够吸收前人的思想,同时自己又可以在项目中大展身手,对自己来说也是好的。

那么我就来说说这个需求吧,因为我们应用是小说阅读器,所以自然阅读页上面肯定是重中之重,而这一块在性能上的要求无疑也是比较高的,如果单纯使用各种View的组合成为一个新的View,明显这样也是可以的,但是这样的性能必然不是很好,因为这里涉及到多层View的嵌套操作,同时对视图的过度渲染也会导致卡慢等的情况出现,所以最好的方式我们最好还是通过在canvas进行操作了。当然这里我给出的只是canvas操作中的一个我遇到问题时的操作,这些问题可能在大牛看来不值一提,但是哪个敢说未来的大牛不会踩一下坑呢?所以我就只能给自己这样的小白归纳一下自己的问题了,当然由于是重构项目,后续肯定还会有各种各样的问题,所以如果有兴趣的朋友可以关注我的博客,后续我会将我重构中的问题一一收集。

正文

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

操作类型相关API备注
绘制颜色drawColor
drawRGB
drawARGB
使用单一颜色填充canvas
绘制基本形状drawPoint
drawPoints
drawLine
drawLines
drawRect
drawRoundRect
drawOval,drawCircle,drawArc
依次是点、线、矩形、圆角矩形
椭圆、圆、圆弧
绘制图片drawBitmap,drawPicture绘制位图和图片
绘制文本drawText,drawPostText
drawTextOnPath
依次是绘制文字、绘制文字时根据制定每个文字位置、
根据路径绘制文字
绘制路径drawPath绘制路径,绘制贝塞尔曲线
时也需要用到该函数
顶点操作drawVertices
drawBitmapMesh
通过对顶点操作可以使图像形变,
drawVertices直接对画布作用、
drawBitmapMesh只对绘制的bitmap作用
画布裁剪clipPath,clipRect设置画布的显示区域
画布快照save,restore,
saveLayerXxx,
restoreToCount,
getSaveCount
依次是保存当前状态、回滚到上一次保存的状态、
保存图层状态、回滚到制定状态、
获取保存次数
画布变换translate,scale,
rotate,skew
依次是位移、缩放、旋转、错切
Matrix矩阵getMatrix,setMatrix,
concat
实际上画布的位移,缩放等操作的都是图像
矩阵Matrix,只不过Matrix比较难以理解
故封装了一些常用的方法
当然这么多的操作,其实都只是列举,实际上这篇文章中,我们用到的仅仅只是drawRoundRect以及drawText而已,其他的操作可以在网上查找更多的资料自行了解,当然也可以继续关注我的后续文章。



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

使用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坐标。



本来以为万无一失的情况,却想不到来了一记晴天霹雳,这蛋疼的位置是什么鬼情况。。。。

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

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


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

然!而!



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进行重新计算,然后再一次绘制文本。。



我们惊讶的发现,问题就这么容易就被解决了,而这算式在度娘上也是能够找到,所以也就不解释了,到此本文所说的问题也就解决了,希望能够帮到大家,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  canvas android
相关文章推荐