自定义 View 之 Canvas 剪裁

前两篇文章调用 Canvas 的 drawXXX 可以绘制出简单的图形了,然后又通过 drawPath 可以绘制出相对复杂的图形了,这篇文章再深入的讲一下 Canvas 对象的使用。

范围剪裁

这个概念很好理解,看过电影里面的狙击手吧,他通过狙击镜看到的内容就是通过剪裁后的,如果把狙击镜换成是五角星的,他看到的内容也就是五角星的,当然狙击镜还有望远镜效果,这里忽略不计。

整个过程可以分为三部分:

  • 狙击镜
  • 原本的风景
  • 狙击镜里的风景

Android 提供了一系列的 clipXXX 方法,顾名思义也就是剪裁的意思了,也就是我们的“狙击镜”:

  • clipPath(Path path):按照路径剪裁
  • clipRect(RectF rect):按照 Rect 剪裁
  • clipRect(Rect rect):按照 Rect 剪裁
  • clipRect(int left, int top, int right, int bottom):按照 Rect 剪裁
  • clipRect(float left, float top, float right, float bottom):按照 Rect 剪裁

例子:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.FILL);
        canvas.clipRect(0, 0, 400, 400);
        canvas.drawRect(0, 0, 800, 800, paint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.FILL);
        
        //绘制路径
        Path path = new Path();
        path.addArc(200, 200, 400, 400, -225, 225);
        path.arcTo(400, 200, 600, 400, -180, 225, false);
        path.lineTo(400, 542);
        //路径剪裁
        canvas.clipPath(path);
        canvas.drawRect(0, 0, 800, 800, paint);
    }

最终绘制效果是前面几个方法裁剪剩下的,相当于狙击镜以外的风景。clipOutXXX 是 API 26 才出现的,无法演示效果,知道就好了。

  • clipOutPath(Path path)
  • clipOutRect(int left, int top, int right, int bottom)
  • clipOutRect(Rect rect)
  • clipOutRect(float left, float top, float right, float bottom)
  • clipOutRect(RectF rect)

裁剪效果:实时上这几个方法在 API 26 已经弃用了,这里将一下 Region.Op op 究竟是干什么的。

  • clipPath(Path path, Region.Op op)
  • clipRect(float left, float top, float right, float bottom, Region.Op op)
  • clipRect(Rect rect, Region.Op op)
  • clipRect(RectF rect, Region.Op op)

这篇博文说的很详细: Android中的裁剪中Region.Op参数的用法

Region.Op 是一个枚举类型,共有以下几种类型:
A:表示第一个裁剪的形状;
B:表示第二次裁剪的形状;

  • DIFFERENCE:是A形状中不同于B的部分显示出来。
  • INTERSECT:是A和B交集的形状
  • REPLACE:是只显示B的形状
  • REVERSE_DIFFERENCE:是B形状中不同于A的部分显示出来,这是没有设置时候默认的
  • UNION:是A和B的全集
  • XOR:是全集形状减去交集形状之后的部分
        //画笔颜色设置为浅蓝色
        mPaint.setColor(Color.parseColor("#D4E9FA"));
        //画笔画一个矩形
        canvas.drawRect(new RectF(0, 0, 300, 300), mPaint);
        //画笔画一个圆形
        canvas.drawCircle(300, 150, 150, mPaint);
        //画笔颜色设置为浅红色
        mPaint.setColor(Color.parseColor("#FF4081"));
        //画布裁剪一个矩形
        canvas.clipRect(new RectF(0, 0, 300, 300));//第一个裁剪一个形状相当于A
        //画布裁剪一个圆形
        Path mPath = new Path();
        mPath.addCircle(300, 150, 150, Path.Direction.CCW);
        /**这里只是改变第二个参数Region.Op.来观察效果*/
        canvas.clipPath(mPath, Region.Op.INTERSECT);//第二个裁剪一个形状相当于B
        //裁剪完之后,画一个长宽全覆盖的红色矩形观察效果
        canvas.drawRect(new RectF(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE), mPaint);

Region.Op.DIFFERENCE

Region.Op.REPLACE

Region.Op.REVERSE_DIFFERENCE

Region.Op.INTERSECT

Region.Op.UNION

Region.Op.XOR