[关闭]
@946898963 2019-10-03T13:43:07.000000Z 字数 6183 阅读 1444

Canvas的裁剪

Android绘图


裁剪

Canvas提供裁剪了的功能,裁剪功能是由Canvas提供的一系列的clip...方法和quickReject方法来完成的。裁剪Clip,即裁剪Canvas图层,我们绘制的东西,只能在裁剪区域的范围能才能显示出来。

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. Paint paint=new Paint();
  4. canvas.save();
  5. canvas.clipRect(new Rect(100,100,300,300));
  6. canvas.drawColor(Color.BLUE);//裁剪区域的rect变为蓝色
  7. canvas.drawRect(new Rect(0,0,100,100), paint);//在裁剪的区域之外,不能显示
  8. canvas.drawCircle(150,150, 50, paint);//在裁剪区域之内,能显示
  9. canvas.restore();
  10. }

裁剪并不像Matrix变换,它相对于mutable bitmap的坐标是不会改变的。所以超出裁剪区域的绘制不会被显示。

注意点

Android中Canvas的的clip有以下两点需要注意:

裁剪的时机

通常我们理解的clip(剪切),是对已经存在的图形进行clip的。但是,在Android上是对Canvas(画布)上进行clip的,而且是要在画图之前对Canvas进行clip,如果画图之后再对Canvas进行clip不会影响到已经画好的图形。

一定要记住clip是针对Canvas而非图形,而且要在画图之前进行clip

Op参数

Op参数针对的对象是之前剪切的区域以及当前要剪切的区域,表示的当前要剪切的区域与之前剪切过的之间的关系。

Op是一个枚举,定义在Region类中。

  1. 假设用region1 去组合region2
  2. public enum Op {
  3. DIFFERENCE(0), //最终区域为region1 与 region2不同的区域
  4. INTERSECT(1), // 最终区域为region1 与 region2相交的区域
  5. UNION(2), //最终区域为region1 与 region2组合一起的区域
  6. XOR(3), //最终区域为region1 与 region2相交之外的区域
  7. REVERSE_DIFFERENCE(4), //最终区域为region2 与 region1不同的区域
  8. REPLACE(5); //最终区域为为region2的区域
  9. }

Op一共有DIFFERENCE,INTERSECT,UNION,XOR, REVERSE_DIFFERENCE, REPLACE六种选择。

  • DIFFERENCE
    之前剪切区域除去当前要剪切的区域。
  • REVERSE_DIFFERENCE
    与DIFFERENCE相反,以当前要剪切的区域为参照物,当前要剪切的区域除去之前剪切过的区域;
  • INTERSECT
    当前要剪切的区域在之前剪切区域内部的部分(也就是取交集)。
  • UNION
    当前要剪切的区域加上之前剪切过内部的部分(也就是取并集)。
  • XOR
    异或,当前要剪切的区域与之前剪切过的进行异或(除去交集部分)。
  • REPLACE
    用当前要剪切的区域代替之前剪切过的区域。
  • 没带Op参数
    效果与INTERSECT的效果一样,两个区域的交集。

裁剪方式

Canvas提供了三种裁剪的方式:

1、最基本的clipRect,裁剪一个矩形。

2、clipPath,裁剪Path包括的范围,Path所包括的范围不是空的才有效。

3、clipRegion(已经被废弃)。

clipRect

clipRect方法重载

  1. public boolean clipRect (Rect rect, Region.Op op)
  2. public boolean clipRect (RectF rect, Region.Op op)
  3. public boolean clipRect (int left, int top, int right, int bottom)
  4. public boolean clipRect (float left, float top, float right, float bottom)
  5. public boolean clipRect (RectF rect)
  6. public boolean clipRect (float left, float top, float right, float bottom, Region.Op op)
  7. public boolean clipRect (Rect rect)

clipRect函数主要是两个部分Rect(一个矩形,或者分拆传入的矩形的四个坐标)和Region.Op。第一个函数我们很好理解,既然进行矩形剪裁,我们需要一个矩形来确认需要剪裁的位置。第二参数就是Region.Op参数,他决定裁剪的效果。

下面我们以clipRect来演示Op参数的作用。下面是的演示的效果图:

此处输入图片的描述

分别传入不同Region.Op参数,对比不同的效果。

DIFFERENCE

  1. canvas.save();
  2. canvas.translate(560, 0);
  3. canvas.clipRect(0, 0, 300, 300);
  4. canvas.clipRect(200, 200, 500, 500, Region.Op.DIFFERENCE);
  5. drawScene(canvas);canvas.restore();

此处输入图片的描述

DIFFERENCE是以第一次剪裁的为基础,在此基础上擦除第二次剪裁的部分(裁出第一次操作,并擦除掉第二次操作)。

INTERSECT

  1. canvas.save();
  2. canvas.translate(560, 0);
  3. canvas.clipRect(0, 0, 300, 300);
  4. canvas.clipRect(200, 200, 500, 500, Region.Op.INTERSECT);
  5. drawScene(canvas);canvas.restore();

此处输入图片的描述

INTERSECT是保留第一次剪裁和第二次剪裁重叠的部分

REPLACE

  1. //分别放开下面三种操作有助于理解
  2. canvas.save();
  3. canvas.translate(560, 0);
  4. //1.第一种操作
  5. canvas.clipRect(0, 0, 300, 300);
  6. canvas.clipRect(200, 200, 500, 500, Region.Op.REPLACE);
  7. //2.第二次操作
  8. //canvas.clipRect(200, 200, 500, 500);
  9. //canvas.clipRect(0, 0, 300, 300, Region.Op.REPLACE);
  10. //3.第三种操作
  11. //canvas.clipRect(0, 0, 300, 300);
  12. drawScene(canvas);
  13. canvas.restore();

此处输入图片的描述

REPLACE是用第二次剪裁替换第一次剪裁(相当于只做了第二次剪裁,丢弃第一次剪裁)

REVERSE_DIFFERENCE

  1. canvas.save();
  2. canvas.translate(560, 0);
  3. canvas.clipRect(0, 0, 300, 300);
  4. canvas.clipRect(200, 200, 500, 500, Region.Op.REVERSE_DIFFERENCE );
  5. drawScene(canvas);canvas.restore();

此处输入图片的描述

REVERSE_DIFFERENCE是以第二次剪裁的为基础,在此基础上擦除第一次剪裁的部分(裁出第二次操作,并擦除掉第一次操作)

UNION

  1. canvas.save();
  2. canvas.translate(560, 0);
  3. canvas.clipRect(0, 0, 300, 300);
  4. canvas.clipRect(200, 200, 500, 500, Region.Op.UNION);
  5. drawScene(canvas);canvas.restore();

此处输入图片的描述

UNION,合并,即保留第一次剪裁和第二次剪裁的并集。

XOR

  1. canvas.save();
  2. canvas.translate(560, 0);
  3. canvas.clipRect(0, 0, 300, 300);
  4. canvas.clipRect(200, 200, 500, 500, Region.Op.XOR);
  5. drawScene(canvas);canvas.restore();

此处输入图片的描述

XOR,异或操作,做出第一次剪裁,并且做出第二次剪裁,在此基础上擦除掉重叠的部分(留下两次操作不重叠的部分)

clipPath

android.graphics包中定义了Point,Rect,Path,Region这几种几何形状。Path可以为有圆弧,椭圆,二次曲线,三次曲线,线段,矩形等基本几何图形或是由这些基本几何图形组合而成,Path可以为开放或是闭合曲线。

我们可以利用该方法从Canvas中“挖”取一块不规则的画布:

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. mPaint.setColor(Color.RED);
  5. mPaint.setStyle(Paint.Style.STROKE);
  6. // 实例化路径
  7. mPath = new Path();
  8. // 移动起点至[50,50]
  9. mPath.moveTo(50, 50);
  10. mPath.lineTo(75, 23);
  11. mPath.lineTo(150, 100);
  12. mPath.lineTo(80, 110);
  13. // 闭合路径
  14. mPath.close();
  15. // 在原始画布上绘制蓝色
  16. canvas.drawColor(Color.BLUE);
  17. // 按照路径进行裁剪
  18. canvas.clipPath(mPath);
  19. // 在裁剪后剩余的画布上绘制红色
  20. canvas.drawColor(Color.RED);
  21. }

此处输入图片的描述

clipRegion(已经被废弃)

Region,中文意思即区域的意思,它表示的是canvas图层上的某一块封闭的区域。

相关的API:

  1. /**构造方法*/
  2. public Region() //创建一个空的区域
  3. public Region(Region region) //拷贝一个region的范围
  4. public Region(Rect r) //创建一个矩形的区域
  5. public Region(int left, int top, int right, int bottom) //创建一个矩形的区域
  6. /**一系列set方法,这些set方法,和上面构造方法形式差不多*/
  7. public void setEmpty() {
  8. public boolean set(Region region)
  9. public boolean set(Rect r)
  10. public boolean set(int left, int top, int right, int bottom)
  11. /*往一个Region中添加一个Path只有这种方法,参数clip代表这个整个Region的区域,在在里面裁剪出path范围的区域*/
  12. public boolean setPath(Path path, Region clip) //用指定的Path和裁剪范围构建一个区域
  13. /**几个判断方法*/
  14. public native boolean isEmpty();//判断该区域是否为空
  15. public native boolean isRect(); //是否是一个矩阵
  16. public native boolean isComplex();//是否是多个矩阵组合
  17. /**一系列的getBound方法,返回一个Region的边界*/
  18. public Rect getBounds()
  19. public boolean getBounds(Rect r)
  20. public Path getBoundaryPath()
  21. public boolean getBoundaryPath(Path path)
  22. /**一系列的判断是否包含某点 和是否相交*/
  23. public native boolean contains(int x, int y);//是否包含某点
  24. public boolean quickContains(Rect r) //是否包含某矩阵
  25. public native boolean quickContains(int left, int top, int right,int bottom) //是否没有包含某矩阵
  26. public boolean quickReject(Rect r) //是否没和该矩阵相交
  27. public native boolean quickReject(int left, int top, int right, int bottom); //是否没和该矩阵相交
  28. public native boolean quickReject(Region rgn); //是否没和该矩阵相交
  29. /**几个平移变换的方法*/
  30. public void translate(int dx, int dy)
  31. public native void translate(int dx, int dy, Region dst);
  32. public void scale(float scale) //hide
  33. public native void scale(float scale, Region dst);//hide
  34. /**一系列组合的方法*/
  35. public final boolean union(Rect r)
  36. public boolean op(Rect r, Op op) {
  37. public boolean op(int left, int top, int right, int bottom, Op op)
  38. public boolean op(Region region, Op op)
  39. public boolean op(Rect rect, Region region, Op op)

与clipRect和clipPath要使用当前的matrix进行变换不同,clipRegion不会进行转换。也就是说canvas的matrix对clipRegion没有影响。这是clipRegion和clipRect和clipPath的最大区别。

  1. Paint paint=new Paint();
  2. canvas.scale(0.5f, 0.5f);
  3. canvas.save();
  4. canvas.clipRect(new Rect(100,100,200,200));//裁剪区域实际大小为50*50
  5. canvas.drawColor(Color.RED);
  6. canvas.restore();
  7. canvas.drawRect(new Rect(0,0,100,100), paint);//矩形实际大小为50*50
  8. canvas.clipRegion(new Region(new Rect(300,300,400,400)));//裁剪区域实际大小为100*100
  9. canvas.drawColor(Color.BLACK);

此处输入图片的描述

可以看到,Canvas的变换 对clipRegion没有作用。

Demo的源码

参考链接:

Android画布剪裁函数clipRect详解

Canvas中clipRect、clipPath和clipRegion 剪切区域的API

Android 2D Graphics学习(二)、Canvas篇2、Canvas裁剪和Region、RegionIterator

android绘图canvas.clipRect()方法的作用

Android中Rect和RectF的区别与联系

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注