安卓中Canvas,paint的Api详解
概述
我们通过在画布上绘画进行类比,如下:
Canvas:相当于画布,Bitmap提供内存,绘的画会保存在Bitmap中。
Paint:相当于画笔。
有了画笔和画笔我们就可以绘画了。
两种坐标系
Canvas绘图中牵扯到两种坐标系:Canvas坐标系与绘图坐标系。
-
Canvas坐标系
Canvas坐标系指的是Canvas本身的坐标系,Canvas坐标系有且只有一个,且是唯一不变的,其坐标原点在View的左上角,从坐标原点向右为x轴的正半轴,从坐标原点向下为y轴的正半轴。 -
绘图坐标系
Canvas的drawXXX方法中传入的各种坐标指的都是绘图坐标系中的坐标,而非Canvas坐标系中的坐标。默认情况下,绘图坐标系与Canvas坐标系完全重合,即初始状况下,绘图坐标系的坐标原点也在View的左上角,从原点向右为x轴正半轴,从原点向下为y轴正半轴。但不同于Canvas坐标系,绘图坐标系并不是一成不变的,可以通过调用Canvas的translate方法平移坐标系,可以通过Canvas的rotate方法旋转坐标系,还可以通过Canvas的scale方法缩放坐标系,而且需要注意的是,translate、rotate、scale的操作都是基于当前绘图坐标系的,而不是基于Canvas坐标系,一旦通过以上方法对坐标系进行了操作之后,当前绘图坐标系就变化了,以后绘图都是基于更新的绘图坐标系了。也就是说,真正对我们绘图有用的是绘图坐标系而非Canvas坐标系。
Canvas保存和还原
Canvas提供了几个方法,让我们可以方便的对Canvas的状态进行更改和还原。
这些方法是:save()、restore()、restoreToCount(int saveCount)。
我们在对Canvas进行平移、旋转、放大等操作时候,可以调用save()方法,将当前修改过的Canvas状态进行保存,调用restore() 方法后,会将Canvas还原成最近的一个save() 的状态。
save()方法还会有一个返回值,我们也可以调用restoreToCount(int saveCount)方法,将这个返回值作为参数传递进去,就可以将Canvas还原成某一个特定的save()状态。
canvas.translate(100,100); // 平移(100,100)
int save1 = canvas.save(); // 保存Canvas状态(状态1)
canvas.scale(2, 2); // 放大2倍
int save2 = canvas.save(); // 保存Canvas状态(状态2)
canvas.restore(); // 返回最新的save状态,即状态2
canvas.restoreToCount(save1); // 手动指定的返回到 状态1
paint的常用设置
参考文章Android Paint,Canvas api 详解
Paint 类常用方法
设置颜色
* 参数一:Android内部定义的有Color类包含了一些常见颜色定义
* Color.RED 或者 getResources().getColor(android.R.color.holo_blue_bright)
* 或者Color.rgb(255,100,100)或者Color.argb(50,255,100,100)
*/
paint.setColor(int color) // 设置颜色
/**
* 参数一:alpha透明值
*/
paint.setARGB(int a, int r, int g, int b) // 设置 Paint对象颜色12345678
设置不透明度
paint.setAlpha(int a) // 设置alpha不透明度,范围为0~2551
设置是否抗锯齿
paint.setAntiAlias(boolean aa) // 是否抗锯齿1
设置文本缩放倍数
/**
* 参数一:,1.0f为原始
*/
paint.setTextScaleX(float scaleX) // 设置文本缩放倍数
设置字体大小
paint.setTextSize(float textSize) // 设置字体大小
设置下划线
paint.setUnderlineText(booleanunderlineText)
// 设置下划线 1
设置实心还是空心
在画面状的图形时,如果Paint的style是FILL,那么绘制的就是填充面;如果是STROKE,那么绘制的就是轮廓线。
/**
* 实心
* /
paint.setStyle(Paint.Style.FILL);
/**
* 空心
* /
paint.setStyle(Paint.Style.STROKE);
设置画笔的粗细
paint.setStrokeWidth(10);
关键点:以上Paint的操作作用在下次绘画的画笔上
画图
画文字
/**
* 参数2:默认是这个字符串的开始在屏幕的x轴位置,如果设置了paint.setTextAlign(Paint.Align.CENTER);那就是字符的中心距屏幕的x轴位置
* 参数2:这个字符baseline在屏幕上的y轴位置
* 参数3:画笔对象
*/
canvas.drawText("开始写字了!",50, 50, p);// 画文本
/**
* 参数2:要从第几个字开始绘制
* 参数3:要绘制到第几个文字
* 参数4:默认是这个字符串的开始在屏幕的x轴位置,如果设置了paint.setTextAlign(Paint.Align.CENTER);那就是字符的中心距屏幕的x轴位置
* 参数5:这个字符baseline在屏幕上的y轴位置
* 参数6:画笔对象
*/
canvas.drawText("开始写字了!",2,5, 50, 50, p);// 画文本,结果为:“写字了”
/**
* 参数2:路径
* 参数3:距离路径开始位置的偏移量
* 参数4:距离路径上下的偏移量(可以为负数)
* 参数5:画笔对象
*/
canvas.drawTextOnPath("1234567890101123123", path, 0, -50, p);
画图片
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
/**
* 参数1:bitmap对象
* 参数2:图像左边坐标点
* 参数3:图像上边坐标点
*/
canvas.drawBitmap(bitmap, 200,300, p);
我在res/drawable目录下放置了一张android的图片,下面对上面的代码进行说明:
-
Canvas的drawBitmap有多个重载方法,最简单的方法签名是:public void drawBitmap (Bitmap
bitmap, float left, float top, Paint
paint)该方法除了传入bitmap对象外,还需要传入left和top,left和top组成了一个坐标,决定了在Canvas中从哪个地方绘制Bitmap。在我们的代码中,left和top都设置为0,所以我们就在Canvas的左上角绘制了bitmap。 -
drawBitmap还有一个比较实用的方法,其方法签名是:public void drawBitmap (Bitmap bitmap,
Rect src, Rect dst, Paint
paint)该方法有两个功能:1.只绘制原有bitmap对象的一部分,2.还可以将要绘制的bitmap缩放到指定的区域。-
只绘制原有bitmap对象的一部分
我们知道Bitmap是一个矩形,其是有宽度和高度的,也就说以bitmap对象本身作为坐标系(原点在bitmap左上角),我们可以构建一个Rect对象,如果满足left为0,top为0,right为bitmap的宽度,bottom为bitmap的高度,那么就说名我们要绘制整个Bitmap。但是有时候我们只想绘制Bitmap的一部分,例如我们上面的图中所示,我们想只绘制Android图像的头部区域怎么办呢?办法是我们构建一个Rect对象,定义我们要绘制Bitmap的哪些部位。
比如我们通过代码srcRect.bottom = (int)(0.33 *
bitmap.getHeight())指定了我们只绘制bitmap对象头部1/3的位置,即Android图像的头部,这样我们用该指定的srcRect绘制bitmap时只绘制了其头部位置。需要特别注意的是,srcRect中left、top、right、bottom的值都是以Bitmap本身的局部坐标系为基础的。将要绘制的bitmap缩放到指定的区域 -
有时候我们需要将原有的bitmap进行放大或缩小,如上图所示,我们将原有图片放大了,这怎么做呢?我们需要指定RectF类型的参数dstRectF,以便告诉Android将srcRect中定义的bitmap缩放到哪里。即Android会将srcRect中定义的bitmap缩放到dstRectF区域范围内。需要注意的是,此处的dstRecF是绘图坐标系中的坐标,不是Bitmap本身的局部坐标系。我们在代码中保证了dstRecF的长宽比与srcRect中的长宽比相同,这样不会导致图片长宽比例变形,效果见上图中的第二个放大的图形。
参考连接添加链接描述
-
一个特殊的调用:
canvas.drawbitmap(bitmap,0,0,null),Paint 的参数为null,表示没有画笔,也就不会进行画画,只有显示图片的功能。
对canvas的进一步理解
Canvas canvas = new Canvas(bmp);
创建了一个包含bmp这个位图的canvas.==canvas的绘制效果会作用于bmp上。
canvas.drawBitmap(mBitmap,0,0,paint);
将mBitmap这个位图用paint画在canvas上,==>直接把bmp的数据变成了mBitmap.