Android中的自绘View的那些事儿(六)之 画布裁剪

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyz_zyx/article/details/78870872

我们在之前的文章中有简单介绍过画布Canvas的使用,它可以使用一系列的draw方法来绘制出各种样式的几何的图形、文字和图片来。今天我们继续探讨Canvas的另一种使用,那就是画布裁剪。什么是画布裁剪?它有点像flash 遮罩层的概念,说白了就是把原来一整块画布裁剪部分出来,然后要绘制出来的东西只能在指定的裁剪区域范围内才能显示出来。

Canvas的裁剪必须要使用save和restore方法:

save: 用于保存Canvas当前的状态。save之后,我们便可以随意对Canvas进行平移、放缩、旋转、错切、裁剪等操作

restore: 用于恢复Canvas之前保存的状态。也就是使save后对Canvas执行的操作对后续的绘制不会造成影响

Canvas的裁剪提供了一些的clip方法:

clipRegion 方法已经不再建议使用

clipPath    裁剪路径,就是指在此路径内绘制

clipRect    裁剪矩形,就是指在此矩形内绘制

示例:

public class MyView extends View {
   public MyView(Context context) {
        this(context, null, 0);
    }
 
   public MyView(Context context, @Nullable AttributeSet attrs) {
       this(context, attrs, 0);
    }
 
   public MyView(Context context, @Nullable AttributeSet attrs, intdefStyleAttr) {
       super(context, attrs, defStyleAttr);
    }
 
   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
 
       Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
       paint.setColor(Color.RED);
 
       Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
       canvas.drawBitmap(bitmap, 0, 0, paint);
    }
}

我们首先来看下正常情况下,我们只在canvas中绘制一张图片。输出效果:

修改onDraw代码:

  @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
 
       Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
       paint.setColor(Color.RED);
 
       int centerX = getWidth() / 2;
       int centerY = getHeight() / 2;
 
       canvas.save();
 
       Path path = new Path();
       path.addCircle(centerX, centerY, 300, Path.Direction.CW);
       canvas.clipPath(path);
       canvas.clipRect(centerX - 50, 100, centerX + 50, getHeight() - 100,Region.Op.UNION);
 
       Bitmap bitmap =BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
       canvas.drawBitmap(bitmap, 0, 0, paint);
 
       canvas.restore();
    }

代码中,我们在开头和结尾分别使用了canvas.save();和canvas.restore();。然后来看中间部分,canvas.clipPath()和canvas.clipRect()两次裁剪了画布。注意clipRect最后的参数Region.Op.UNION,它是表示两个区域叠加。运行效果:

再修改onDraw代码:

   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
 
       Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
       paint.setColor(Color.RED);
 
       int centerX = getWidth() / 2;
       int centerY = getHeight() / 2;
 
       canvas.save();
 
       Path path = new Path();
       path.addCircle(centerX, centerY, 300, Path.Direction.CW);
       canvas.clipPath(path);
       canvas.clipRect(centerX - 50, 100, centerX + 50, getHeight() - 100,Region.Op.UNION);
 
       canvas.rotate(45, centerX, centerY);                // 旋转
       canvas.translate(100, 100);                         // 平移
       canvas.scale(0.5f, 0.5f);                           // 缩放
       canvas.skew(0, 1);                                  // 错切
 
       Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
       canvas.drawBitmap(bitmap, 0, 0, paint);
 
       canvas.restore();
    }

本次代码中,我们加入了旋转(rotate)、平移(translate)、缩放(scale)以及错切(skew)效果。运行效果:

注意

在Android4.0及之前的手机中,因为硬件加速等原因,在使用clipPath时很有可能会发生UnsupportedOperationException异常,像下面:

java.lang.UnsupportedOperationException
atandroid.view.GLES20Canvas.clipPath(GLES20Canvas.java:287)
atcom.myapp.MyCustomView.onDraw(SourceFile:288)
at android.view.View.draw(View.java:9310)
at android.view.View.getDisplayList(View.java:8773)
atandroid.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2298)

所以在使用画布裁剪中最好加入捕捉UnsupportedOperationException异常的处理和系统判断过滤。


猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/78870872