Android canvas

1.Canvas

Canvas指画布,表现在屏幕上就是一块区域,可以在上面使用各种API绘制想要的东西。

canvas内部维持了一个mutable Bitmap,所以它可以使用颜色值去填充整个Bitmap,此外canvas也可以使用画笔去填充整个Bitmap。这两种填充方式都会受限于clip的范围。

canvas虽然内部保持了一个Bitmap,但是它本身并不代表那个Bitmap,而更像是一个图层。我们对这个图层的平移、旋转和缩放等操作并不影响内部的Bitmap,仅仅是改变了该图层相对于内部Bitmap的坐标位置、比例和方向而已。

在Android中,获得Canvas对象主要有三种方法:

①继承View,并重写onDraw()方法。View的Canvas对象会被当做参数传递过来,在这个Canvas上进行的操作会直接反映在View中。

②调用SurfaceHolder.lockCanvas()返回一个Canvas对象。

③通过构造方法创建一个Canvas对象。

Bitmap bitmap = Bitmap.createBitmap(100f, 100f, Config.ARGB_8888); //得到一个Bitmap对象,也可以使用别的方式得到。但是要注意,该bitmap一定要是mutable(异变的)      

Canvas canvas = new Canvas(bitmap);

 

Canvas的坐标系:

画布以左上角为原点(0,0),向右为X轴的正方向,向下为Y轴的正方向:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_8,color_FFFFFF,t_70,g_se,x_16

Canvas的绘图操作:

绘制颜色 drawColor、drawRGB、drawARGB

绘制圆 drawCircle

绘制点 drawPoint

绘制直线 drawLine

绘制矩形 drawRect

绘制圆角矩形 drawRoundRect

绘制椭圆 drawOval

绘制弧形 drawArc

绘制文本 drawText

沿Path路径绘制文本 drawTextOnPath

绘制位图 drawBitmap

使用canvas.drawXXX时,系统会在一个新的透明区域绘制内容,然后迅速与屏幕当前显示内容进行重叠,这个重叠的过程也会受xfermode或blendmode的影响。

 

2.PorterDuffXfermode

android.graphics.PorterDuffXfermode类继承自android.graphics.Xfermode。在Android中用Canvas进行绘图时,可以通过使用PorterDuffXfermode将所绘制的图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas中最终的像素颜色值,这样会创建很多有趣的效果。当使用PorterDuffXfermode时,需要将其作为参数传给Paint.setXfermode(Xfermode xfermode)方法,这样在用该画笔paint进行绘图时,Android就会使用传入的PorterDuffXfermode,如果不想再使用Xfermode,那么可以执行Paint.setXfermode(null)。

举个例子:

①不使用Xfermode:

@Override

protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    canvas.drawARGB(255, 139, 197, 186);//设置背景色

    int canvasWidth = canvas.getWidth();

    int r = canvasWidth / 3;

    //绘制黄色的圆形

    paint.setColor(Color.YELLOW);

    canvas.drawCircle(r, r, r, paint);

    //绘制蓝色的矩形

    paint.setColor(Color.BLUE);

    canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint);

}

重写View的onDraw方法,首先将View的背景色设置为绿色,然后绘制了一个黄色的圆形,然后再绘制一个蓝色的矩形,效果如下所示:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

上面演示就是Canvas正常的绘图流程,没有使用PorterDuffXfermode。简单分析一下上面这段代码:

1)首先调用了canvas.drawARGB(255, 139, 197, 186)方法将整个Canvas都绘制成一个颜色,在执行完这句代码后,canvas上所有像素的颜色值的ARGB颜色都是(255,139,197,186),由于像素的alpha分量是255而不是0,所以此时所有像素都不透明。

2)当执行了canvas.drawCircle(r, r, r, paint)之后,Android会在所画圆的位置用黄颜色的画笔绘制一个黄色的圆形,此时整个圆形内部所有的像素颜色值的ARGB颜色都是0xFFFFFF00(YELLOW),然后用这些黄色的像素替换掉Canvas中对应的同一位置中颜色值ARGB为(255,139,197,186)的像素,这样就将黄色圆形绘制到Canvas上了。

3)当执行了canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint)之后,Android会在所画矩形的位置用蓝色的画笔绘制一个蓝色的矩形,此时整个矩形内部所有的像素颜色值的ARGB颜色都是0xFF0000FF(BLUE),然后用这些蓝色的像素替换掉Canvas中对应的同一位置中的像素,这样黄色的圆中的右下角部分的像素与其他一些背景色像素就被蓝色像素替换了,这样就将蓝色矩形绘制到Canvas上了。

这个过程虽然简单,但是了解Canvas绘图时具体的像素更新过程是真正理解PorterDuffXfermode的工作原理的基础。

②接下来,使用PorterDuffXfermode对上面的代码进行修改:

@Override

protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    canvas.drawARGB(255, 139, 197, 186);//设置背景色

    int canvasWidth = canvas.getWidth();

    int r = canvasWidth / 3;

    //正常绘制黄色的圆形

    paint.setColor(Color.YELLOW);

    canvas.drawCircle(r, r, r, paint);

    //使用CLEAR作为PorterDuffXfermode绘制蓝色的矩形

    paint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR));

    paint.setColor(Color.BLUE);

    canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint);

    //最后将画笔去除Xfermode

    paint.setXfermode(null);

}

最终效果还取决于是否关闭了硬件加速,因为PorterDuff.Mode.CLEAR不支持硬件加速:

//关闭硬件加速

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

关闭硬件加速的效果:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

 不关闭硬件加速的效果:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

同样对以上代码进行一下分析:

1)首先调用了canvas.drawARGB(255, 139, 197, 186)方法将整个Canvas都绘制成一个颜色,此时所有像素都不透明。

2)然后通过调用canvas.drawCircle(r, r, r, paint)绘制了一个黄色的圆形到Canvas上面。

3)然后执行代码paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)),将画笔的PorterDuff模式设置为CLEAR。

4)然后调用canvas.drawRect(r, r, r * 2.7f, r * 2.7f, paint)方法绘制蓝色的矩形,但是最终界面上出现了一个白色/黑色的矩形。

5)在绘制完成后,调用paint.setXfermode(null)将画笔去除Xfermode。

具体分析一下白色/黑色矩形出现的原因:一般在调用canvas.drawXXX()方法时都会传入一个画笔Paint对象,Android在绘图时会先检查该画笔Paint对象有没有设置Xfermode,如果没有设置Xfermode,那么直接将绘制的图形覆盖Canvas对应位置原有的像素;如果设置了Xfermode,那么会按照Xfermode具体的规则来更新Canvas中对应位置的像素颜色。就本例来说,在执行canvas.dr

  • 17
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值