Android Canvas
2016-04-06 本文已影响1092人
RazorZ
Android官方源码中对Canvas的描述是:“Canvas类容纳所有和Draw(绘制)相关方法。为了去Draw些东西,你需要具备4个基础要素:1个Bitmap用来承载像素信息,1个Canvas用来管理Draw相关方法(写入Bitmap中),1个绘图基元(例如,Rect,Path,text,Bitmap),1个画笔(用于描绘图像的颜色和风格)。
这和我们日常理解的绘画异曲同工,Bitmap作为画布,Canvas管理着绘画的手法,绘图基元代表着要绘制的目标,Paint就是你手里的画笔和颜料。
如何得到1个Canvas对象
- 之前提到的onDraw方法的入口参数就是Canvas,我们用变量承载它,就可以使用,而我们操作这个Canvas最终的效果会直接反应在这个View上。
- SurfaceView是View的继承了,其内部有专门的线程来完成画图的工作,而不用像View一样需要等待刷新,主要用在游戏和高品质动画方面。既然是View的继承类,SurfaceView自然可以获取到Canvas的对象,方式是通过调用SurfaceView的好基友SurfaceHolder的lockCanvas()方法。
- 当然,除了获取View或SurfaceView自带的现成的Canvas对象,我们还可以自己创建。从4大基本要素我们就可以知道,1个Canvas对象一定要结合1个Bitmap对象。所以一定要为新建的Canvas对象设置1个Bitmap对象。
/**
* 得到一个Bitmap对象,当然也可以使用别的方式得到。但是要注意,改bitmap一定要是mutable(异变的)
* mutable : 易变的,不定的
* mutable 作用 : 控制bitmap的setPixel方法能否使用,也就是外界能否修改bitmap的像素。
* Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888) 为 mutable 为true
* BimapFactory.decodeResource() 得到的mutable 为false, 要想其为true
* 一般会BimtapFactory.decodeResource().copy(configu_argb_8888, true);
* 先new一个Canvas对象,在调用setBitmap方法,一样的效果
* Canvas c = new Canvas();
* c.setBitmap(b);
*/
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(b);
Canvas能画些什么
Canvas类提供了若干draw……的方法,从字面上我们就可以知道用这些方法我们可以绘制哪些东西。
填充
Canvas内部维持了一个mutable Bitmap,所以我们可以用颜色来填充整个Bitmap。而填充的范围受限于clip的范围。
- drawRGB(int r, int g, int b):r-红色要素(0255),g-绿色要素(0255),b-蓝色要素(0~255)。
- drawARGB(int a, int r, int g, int b):a-透明度(0255),r-红色要素(0255),g-绿色要素(0255),b-蓝色要素(0255)。
- drawColor(int color):这里的color要为16进制的颜色号,例如:0xFF000000,共8位,两位一组从左到右分别为ARGB,具体含义同上。若要使用“#FF000000”这样的色号,可以调用Color.parseColor(String colorString)方法来进行转换。
- drawColor(int color, PorterDuff.Mode mode):color同上,PorterDuff.Mode比较有意思,有很多种模式,每一种模式都会有特定的效果,感兴趣的朋友可以自行了解一下。
- drawPaint(Paint paint):Canvas同样可以用画笔来填充Bitmap,当然也受限于clip的范围。
绘制图形
- canvas.drawArc (扇形)
- canvas.drawCircle(圆)
- canvas.drawOval(椭圆)
- canvas.drawLine(线)
- canvas.drawPoint(点)
- canvas.drawRect(矩形)
- canvas.drawRoundRect(圆角矩形)
- canvas.drawVertices(顶点)
- cnavas.drawPath(路径)
绘制图片
- canvas.drawBitmap(位图)
- canvas.drawPicture(图片)
文本
- canvas.drawText
Canvas的变换
Canvas不仅仅可以draw一些图形、图片,其本身也提供了可操作的方法:rorate(旋转)、scale(压缩)、translate(平移)、skew(扭曲)等。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
canvas.scale(0.5f, 0.5f);//缩放了
canvas.drawRect(new Rect(400, 400, 600, 600), new Paint());
canvas.translate(600, 600);//平移了
canvas.rotate(45);//旋转了
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
canvas.translate(200, 200);
canvas.skew(.5f, .5f);//扭曲了
canvas.drawRect(new Rect(0, 0, 200, 200), new Paint());
}
![](https://img.haomeiwen.com/i1672049/06e01f29f30c229f.png)
Canvas的保存和回滚
为了配合Canvas本身的变换操作,Canvas提供了保持当前状态和回滚的方法。来个小例子。
我们准备画一个表盘,那么我们就有两种实现的思路:
- 表盘上有60个刻度,每个刻度之间间隔6°,这是有规律的,那么我们就可以利用三角函数的知识来把刻度的两个坐标求出来,再利用drawLine画到Canvas上。考验你逻辑思维和数学功底的时候到了,不用仔细想就能知道这个方法有点麻烦。
- 如果不喜欢第一种方法,那么我们可以尝试一下这一种。Canvas提供了旋转操作的方法,也提供了保存和回复状态的方法,那么我们就用这些搭配起来。首先我在(100,0)和(100,10)两个坐标之间画一条竖线,很简单,整点的刻度就出来了。之后先将Canvas的状态保存起来,在(100,0)和(100,10)两个坐标之间画一条竖线,回复Canvas的状态,一分钟的刻度就出来了。以此类推,思路是不是很简单。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < 360; i = i + 6) {
canvas.save();
canvas.rotate(i, 100, 100);
canvas.drawLine(100, 0, 100, 10, new Paint());
canvas.restore();
}
}
![](http://upload-images.jianshu.io/upload_images/1672049-d1801e79b5834f46.png)