带你玩转自定义view系列--Canvas之Path的详解
标签: 带你玩转自定义view系列--Canvas之Path的详解 Android博客 51CTO博客
2023-07-21 18:24:29 81浏览
Canvas之Path的详解
Canvas的绘制图形只能绘制一些常规的,比如点、线、圆、椭圆、矩形等的。如果想要绘制更复杂的图形,那么就得靠Path了。
Path的定义: Path类将多种符合路径(多个轮廓,如直线段、二次曲线、立方曲线等)封装在其内部的几何路径。
Path的绘制: 通过设置Paint.Style的FILL(只描内容)、STROKE(只描边)、FILL_AND_STROKE(描边和内容),然后调用canvas.drawPath(path, paint);Path还可以用于剪切或者在路径上绘制文本canvas.drawTextOnPath()。
Path有两个构造函数
Path() // 空的构造函数Path(Path src) //创建一个新的路径,并且从src路径里赋值内容
Path一些常用的API:
| 功能分类 | Path的常用API | 备注 | | 线操作 | lineTo、rLineTo | 绘制线 | | 点操作 | moveTo、rMoveTo | 改变后面操作的起始点位置 | | setLastPoint | 改变前面操作中最后点的位置 | | 常规图形操作 | addRect | 绘制矩形 | | addRoundRect | 绘制圆角矩形 | | addCircle | 绘制圆 | | addOval | 绘制椭圆 | | addArc、arcTo | 绘制圆弧 | | 闭合path操作 | close | 如果连接Path起点和终点能形成一个闭合图形,则会将起点和终点连接起来形成一个闭合图形 | | 贝塞尔曲线 | quadTo、rQuadTo、cubicTo、rCubicTo | 贝塞尔曲线 |
线操作
lineTo(float x, float y) //添加当前点到目标点(x,y)构成的直线到pathrLineTo(float dx, float dy) //基于当前坐标系,即以path最后的那个点//为坐标系原点(0,0),如果前面没有path的点,默认是屏幕左上角(0,0)
注:lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点(0,0)
演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //屏幕左上角(0,0)到(200,200)画一条直线 path.lineTo(200, 200); //(200, 200)到(200, 400)画一条直线 path.lineTo(200, 400); //以(200, 400)为起始点(0,0)偏移量为(200, 400)画一条直线, //其终点坐标实际在屏幕的位置为(400, 800) path.rLineTo(400, 800); canvas.drawPath(path, paint);
结果:
image
点操作
moveTo(float x, float y) //改变接下来操作的起点位置为(x,y)rMoveTo(float dx, float dy) //接下来要操作的起点位置为(x+dx,y+dy)setLastPoint(float dx, float dy) //改变前一步操作点的位置,会改变前一步的操作
先对比一下**moveTo()和rMoveTo()**的区别,演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //将坐标系原点从(0,0)移动到(200,200) path.moveTo(200,200); //画从(200,200)到(400,400)之间的直线 path.lineTo(400, 400);// path.rMoveTo(100, 0); //暂时注释 path.lineTo(800, 400); canvas.drawPath(path, paint);
暂时注释了rMoveTo()方法,看看结果:
image
然后解掉rMoveTo()方法的注释,意思是下一步的起点位置由(400, 400)变为(400+100, 400+0),即(500,400),结果:
image
再来看看**moveTo()和setLastPoint()**的区别,同样以上的代码,加上path.setLastPoint(800, 200)方法:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //将坐标系原点从(0,0)移动到(200,200) path.moveTo(200,200); //画从(200,200)到(400,400)之间的直线 path.lineTo(400, 400); path.setLastPoint(800, 200); path.lineTo(800, 400); canvas.drawPath(path, paint);
结果:
image
红线原本是设置setLastPoint(800, 200)之前的路径,在设置之后,影响到了前一步lineTo(400, 400)的操作,使之变成了lineTo(800, 200),结果就如图了。
**得出结论:**rMoveTo()影响的是后面操作的起点位置,并不会影响之前的操作;而setLastPoint()改变前一步操作最后一个点的位置,不仅影响前一步操作,同时也会影响后一步操作。
绘制常规图形
//绘制圆addCircle(float x, float y, float radius, Direction dir) //绘制椭圆addOval(RectF oval, Direction dir)addOval(float left, float top, float right, float bottom, Direction dir) //绘制矩形addRect(RectF rect, Direction dir) addRect(float left, float top, float right, float bottom, Direction dir) //绘制圆角矩形addRoundRect(RectF rect, float rx, float ry, Direction dir) addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)addRoundRect(RectF rect, float[] radii, Direction dir)addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)
所有API里面都有一个共同的参数Direction:
Direction |
备注 |
Path.Direction.CCW |
counter-clockwise ,沿逆时针方向绘制 |
clockwise ,沿顺时针方向绘制 |
Direction其用法演示:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(2f); paint.setTextSize(40f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //以(600,600)为圆心,300为半径绘制圆 //Path.Direction.CW顺时针绘制圆 Path.Direction.CCW逆时针绘制圆 path.addCircle(600, 600, 300, Path.Direction.CCW); //沿path绘制文字 canvas.drawTextOnPath("我是Layne,在测试Direction,这是CCW逆时针绘制圆", path, 0, 0, paint); canvas.drawPath(path, paint);
结果对比:
image
其他图形绘制示例:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //以(400,200)为圆心,半径为100绘制圆 path.addCircle(550, 200, 100, Path.Direction.CW); //绘制椭圆 RectF rectF = new RectF(100, 350, 500, 600); //第一种方法绘制椭圆 path.addOval(rectF, Path.Direction.CW); //第二种方法绘制椭圆 path.addOval(600, 350, 1000, 600, Path.Direction.CW); //绘制矩形 RectF rect = new RectF(100, 650, 500, 900); //第一种方法绘制矩形 path.addRect(rect, Path.Direction.CW); //第一种方法绘制矩形 path.addRect(600, 650, 1000, 900, Path.Direction.CCW); //绘制圆角矩形 RectF roundRect = new RectF(100, 950, 300, 1100); //第一种方法绘制圆角矩形 path.addRoundRect(roundRect, 20, 20, Path.Direction.CW); //第二种方法绘制圆角矩形 path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW); //第三种方法绘制圆角矩形 //float[] radii中有8个值,依次为左上角,右上角,右下角,左下角的rx,ry RectF roundRectT = new RectF(600, 950, 800, 1100); path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW); //第四种方法绘制圆角矩形 path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW); canvas.drawPath(path, paint);
结果:
image
绘制圆弧
//绘制圆弧addArc(RectF oval, float startAngle, float sweepAngle)addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)//forceMoveTo:是否强制将path最后一个点移动到圆弧起点,//true是强制移动,即为不连接两个点;false则连接两个点arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)arcTo(RectF oval, float startAngle, float sweepAngle)arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)
addArc()和arcTo()都是添加圆弧到path中,不过他们之间还是有区别的。addArc()是直接添加圆弧到path中;而arcTo()会判断要绘制圆弧的起点与绘制圆弧之前path中最后的点是否是同一个点,如果不是同一个点的话,就会连接两个点。
演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(20f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //在F(400, 200, 700, 500)区域内绘制一个270度的圆弧 RectF rectF = new RectF(400, 200, 700, 500); path.addArc(rectF, 0, 270); //在(400, 600, 600, 800)区域内绘制一个90度的圆弧,并且不连接两个点 RectF rectFTo = new RectF(400, 600, 700, 900); path.arcTo(rectFTo, 0, 180, true); //等价于path.addArc(rectFTo, 0, 180); canvas.drawPath(path, paint);
结果:
image
把上面代码修改成连接两点:
path.arcTo(rectFTo, 0, 180, false); //等价于path.addArc(rectFTo, 0, 180);
结果:
image
闭合path操作
如果path的重点和起始点不是同一个点的话,那么path.close()就会连接这两个点,形成一个封闭的图形。演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(20f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); //在F(400, 200, 700, 500)区域内绘制一个270度的圆弧 RectF rectF = new RectF(400, 200, 700, 500); path.addArc(rectF, 0, 270);// path.close(); //先注释 canvas.drawPath(path, paint);
结果:
image
接下来解掉path.close()的注释,再运行一次,结果:
image
贝塞尔曲线
贝塞尔曲线就麻烦多了,也复杂多了。这里不详细说明了,再网上找到一篇说明比较详细的文章。 安卓自定义View进阶 - 贝塞尔曲线:(https://blog.csdn.net/u013831257/article/details/51281136)
这里直接复制了里面的二阶曲线的实现:
public class CanvasView extends View { private Paint mPaint; private int centerX, centerY; private PointF start, end, control; public CanvasView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(8); mPaint.setStyle(Paint.Style.STROKE); mPaint.setTextSize(60); start = new PointF(0, 0); end = new PointF(0, 0); control = new PointF(0, 0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); centerX = w / 2; centerY = h / 2; // 初始化数据点和控制点的位置 start.x = centerX - 200; start.y = centerY; end.x = centerX + 200; end.y = centerY; control.x = centerX; control.y = centerY - 100; } @Override public boolean onTouchEvent(MotionEvent event) { // 根据触摸位置更新控制点,并提示重绘 control.x = event.getX(); control.y = event.getY(); invalidate();//刷新View,重新绘制 return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制数据点和控制点 mPaint.setColor(Color.GRAY); mPaint.setStrokeWidth(20); canvas.drawPoint(start.x, start.y, mPaint); canvas.drawPoint(end.x, end.y, mPaint); canvas.drawPoint(control.x, control.y, mPaint); // 绘制辅助线 mPaint.setStrokeWidth(4); canvas.drawLine(start.x, start.y, control.x, control.y, mPaint); canvas.drawLine(end.x, end.y, control.x, control.y, mPaint); // 绘制贝塞尔曲线 mPaint.setColor(Color.RED); mPaint.setStrokeWidth(8); Path path = new Path(); path.moveTo(start.x, start.y); path.quadTo(control.x, control.y, end.x, end.y); canvas.drawPath(path, mPaint); }}
结果:
image
PathMeasure的详解
PathMeasure是什么? PathMeasure是用来对Path进行测量的工具,一般来说PathMeasure是和Path配合着使用的。通过PathMeasure,我们可以知道Path路径上某讴歌点的坐标、Path的长度等的。
PathMeasure有两个构造函数:
//构建一个空的PathMeasurePathMeasure() //构建一个PathMeasure并关联一个指定的创建好的PathPathMeasure(Path path, boolean forceClosed)
无参构造函数PathMeasure()在使用前必须调用setPath(Path path, boolean forceClosed)来关联一个Path。其实就是等价于有参数的构造函数PathMeasure(Path path, boolean forceClosed)了。如果关联之后的Path有所更改,那么就需要调用setPath(Path path, boolean forceClosed)重新关联。
PathMeasure常用的API:
setPath(Path path, boolean forceClosed) isClosed()getLength()getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)getMatrix(float distance, Matrix matrix, int flags)getPosTan(float distance, float pos[], float tan[])nextContour()
setPath(Path path, boolean forceClosed): 此方法是关联一个预先创建好的Path。第二个参数forceClosed如果为true,并且关联的Path未闭合时,测量的Path长度可能比Path实际长度长一点,因为测量的是Path闭合的长度。但是关联的Path不会有任何变化
isClosed(): 判断关联的Path是否是闭合状态。如果forceClosed为true,那么此方法一定返回true。
getLength(): 返回已关联的Path总长度。如果setPath()时设置的forceClosed为true,则返回的值可能会比实际长度的长。
getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo): 截取Path的一段。如果截取成功,则返回true,反之则返回false。
参数 |
备注 |
startD |
起点在Path的位置,取值范围0<=startD < stopD<=getLength() |
stopD |
终点在Path的位置,取值范围0<=startD < stopD<=getLength() |
dst |
将截取的path的片段添加到dst中 |
startWithMoveTo |
起点是否使用MoveTo,如果为true,则截取的path的第一个点不会变化,截取的path也不会改变,如果为false,则截取的path可能会发生形变。 |
注: 1.如果截取Path的长度为0,则返回false,大于0则返回true; 2.startD、stopD必须为和法制(0,getLength()),如果startD>=stopD,则返回false; 3.在Android 4.4或之前的版本在开启硬件加速时,绘制可能会不显示,请关闭硬件加速或者给dst添加一个简单的操作,如:dst.rLineTo(0,0)
演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 //初始化Path并顺时针绘制一个矩形 Path sourcePath = new Path(); sourcePath.addRect(300, 300, 800, 800, Path.Direction.CW); PathMeasure measure = new PathMeasure(); measure.setPath(sourcePath, false); Log.e("PathMeasure", "measure.getLength():" + measure.getLength()); canvas.drawPath(sourcePath, paint);
结果:
image
image
现在要截取上图中的下半部分,总长度是2000,中间的部分就是[750,1750]。演示一下:
//初始化Path并顺时针绘制一个矩形 Path sourcePath = new Path(); sourcePath.addRect(300, 300, 800, 800, Path.Direction.CW); PathMeasure measure = new PathMeasure(); measure.setPath(sourcePath, false);// Log.e("PathMeasure", "measure.getLength():" + measure.getLength());// canvas.drawPath(sourcePath, paint); //初始化一个空的Path Path dstPath = new Path(); //截取sourcePath的一部分添加到dstPath中 measure.getSegment(750, 1750, dstPath, true); dstPath.rLineTo(0, 0);//真机刚刚好是4.4版本的,加个简单的操作 canvas.drawPath(dstPath, paint);
结果:
image
上面代码中的dstPath初始化完之后,并没有内容的,试试有内容的情况:
//初始化Path并顺时针绘制一个矩形 Path sourcePath = new Path(); sourcePath.addRect(300, 300, 800, 800, Path.Direction.CW); PathMeasure measure = new PathMeasure(); measure.setPath(sourcePath, false);// Log.e("PathMeasure", "measure.getLength():" + measure.getLength());// canvas.drawPath(sourcePath, paint); //初始化一个空的Path Path dstPath = new Path(); dstPath.rLineTo(200, 200); dstPath.lineTo(800, 200); //截取sourcePath的一部分添加到dstPath中 measure.getSegment(750, 1750, dstPath, true); canvas.drawPath(dstPath, paint);
结果:
image
有意思的是,将dstPath的rLineTo()和lineTo()放在getSegment()之后,后面内容的起点就成了getSegment()的终点了。演示一下:
//初始化Path并顺时针绘制一个矩形 Path sourcePath = new Path(); sourcePath.addRect(300, 300, 800, 800, Path.Direction.CW); PathMeasure measure = new PathMeasure(); measure.setPath(sourcePath, false);// Log.e("PathMeasure", "measure.getLength():" + measure.getLength());// canvas.drawPath(sourcePath, paint); //初始化一个空的Path Path dstPath = new Path(); //截取sourcePath的一部分添加到dstPath中 measure.getSegment(750, 1750, dstPath, true); dstPath.rLineTo(200, 200); dstPath.lineTo(800, 200); canvas.drawPath(dstPath, paint);
结果:
image
再把上面代码中的getSegment()的startWithMoveTo参数改成false会变成什么样呢?演示一下:
//初始化Path并顺时针绘制一个矩形 Path sourcePath = new Path(); sourcePath.addRect(300, 300, 800, 800, Path.Direction.CW); PathMeasure measure = new PathMeasure(); measure.setPath(sourcePath, false);// Log.e("PathMeasure", "measure.getLength():" + measure.getLength());// canvas.drawPath(sourcePath, paint); //初始化一个空的Path Path dstPath = new Path(); //为了易于理解,把这两个方法放回getSegment()前面 dstPath.rLineTo(200, 200); dstPath.lineTo(800, 200); //截取sourcePath的一部分添加到dstPath中 measure.getSegment(750, 1750, dstPath, false); canvas.drawPath(dstPath, paint);
结果:
image
和上上结果对比可得出:startWithMoveTo参数为true时,被截取的path片段会保持原状;startWithMoveTo参数为false时,会将截取的path片段的起始点移动到dstPath的终点,以保持dstPath的连续性。
getMatrix(float distance, Matrix matrix, int flags): 距离Path起始点的一段长度distance,通过计算得到该位置坐标并返回一个处理好的矩阵,该矩阵以左上角为旋转点,如果Path不存在或者长度为0,该方法返回false。
参数 |
备注 |
distance |
距离Path起始点的距离,取值范围0 <= distance <=getLength() |
matrix |
根据 flags封装matrix,flags不同,存入matrix的就不同 |
flags |
PathMeasure.POSITION_MATRIX_FLAG:位置信息 ,PathMeasure.TANGENT_MATRIX_FLAG:切边信息,方位角信息,使得图片按path旋转。 |
getPosTan(float distance, float pos[], float tan[]): 距离Path起始点的长度distance,通过计算返回该长度在Path上的坐标及该坐标的正切值分别复制给pos[]、tan[]
参数 |
备注 |
distance |
距离Path起始点的距离,取值范围0 <= distance <= getLength() |
pos[] |
distance在path上的坐标,即pos[]存的该点的坐标x,y值 |
tan[] |
distance在path上对应坐标点在path上的方向,tan[0]是邻边边长,tan[1]是对边边长。通过Math.atan2(tan[1], tan[0])*180.0/Math.PI 可以得到正切角的弧度值。 |
nextContour(): 如果Path有多条曲线组成,且彼此不连接,那么getLength()、getSegment()、getMatrix()和getPosTan()这些方法,都只是针对当前正在操作的。举个例子,Path由多条曲线组成,且彼此不连接,那么getLength()返回的只是当前操作曲线的长度,并不是所有曲线的长度。那么怎么获取下一条曲线的长度呢?这时就得用nextContour()跳转到下一条曲线了,跳转成功返回true,失败就返回false。演示一下:
Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); //只描边 paint.setColor(Color.BLUE); paint.setStrokeWidth(10f); paint.setAntiAlias(true); //设置抗锯齿 paint.setDither(true); //设置防抖动 Path path = new Path(); PathMeasure measure = new PathMeasure(); //绘制一条从(100,100)到(900,100)的直线,长度为800 path.moveTo(100, 100); path.lineTo(900, 100); //绘制一条从(100,200)到(500,100)的直线,长度为400 path.moveTo(100, 200); path.lineTo(500, 200); measure.setPath(path, false); //输出第一条曲线的长度 Log.e("PathMeasure", "measure.getLength():" + measure.getLength()); measure.nextContour(); //跳转到下一条曲线 //输出第二条曲线的长度 Log.e("PathMeasure", "next measure.getLength():" + measure.getLength()); canvas.drawPath(path, paint);
输出的结果:
image
Region区域
Region 在 Android 的绘制中是区域的意思,使用 Region 可以对图形进行很多操作,比如区域的合并,取交集、或抑或等等。
Region 的构造函数有以下四个:
public Region() //无参构造public Region(Region region) //传入指定一个区域public Region(Rect r) //传入一个矩形public Region(int left, int top, int right, int bottom) //传入两个点,其实就是一个矩形
方法二就是传入一个 Region 指定区域,方法三四都是一个意思,就是传入一个矩形。方法一是无参构造,Region 是可以后期指定代表区域的,以下是后期指定代表区域的方法:
public void setEmpty() //清空public boolean set(Region region) public boolean set(Rect r) public boolean set(int left, int top, int right, int bottom) public boolean setPath(Path path, Region clip)//将path和clip的两个区域取交集
以上的 set 方法都是指定新的区域来代替 Region 对象中原有的区域。
还有以上的方法在绘制图像过程中,cavas 没有直接绘制 Region 的方法,要绘制指定的 Region 需要使用 RegionIterator,RegionIterator 是一个迭代器,其主要作用是从指定的 Region 中获取 rect,也就是矩形。
1SetPath()
public boolean setPath(Path path, Region clip)//将path和clip的两个区域取交集
如注释,该方法的作用是将 path 区域和 clip 区域取交集。接下来演示一下:
public class RegionView extends View { private Paint mPaint; public RegionView(Context context) { this(context, null); } public RegionView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RegionView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } private void initPaint() { mPaint = new Paint(); mPaint.setColor(Color.GREEN); mPaint.setStrokeWidth(3); mPaint.setStyle(Paint.Style.STROKE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画一个圆 Path path = new Path(); path.addCircle(500, 500, 300, Path.Direction.CW); //指定一个区域,然后取与圆的交集 Region region = new Region(); region.setPath(path, new Region(0, 0, 1000, 1000)); //绘制交集区域 RegionIterator iterator = new RegionIterator(region); Rect rect = new Rect(); while (iterator.next(rect)) { canvas.drawRect(rect, mPaint); } }}
上面代码可以看到,ReginIterator 类是依次取出构成区域大小不同的矩形,然后由 cavas 绘制,从而组成一个图形,下面看结果:
image
从图中可以看出,圆形是由若干个矩形组成,依次排列成圆形,因为代码中画笔使用的风格是 STROKE(描边),所以中间一些就是空的。如果使用 Fill(填充),那么组成的就是一个实心圆。
2区域的操作
public final boolean union(Rect r) public boolean op(Rect r, Op op) { public boolean op(int left, int top, int right, int bottom, Op op) public boolean op(Region region, Op op) public boolean op(Rect rect, Region region, Op op)
区域的操作有很多种,上面第一种 union() 主要是取并集,后面的 op() 方法就是 operation,操作的意思,具体如何操作?还要看后面的 op 参数来决定。Op 是一个枚举类,具体取值如下:
public enum Op { DIFFERENCE(0), //取补集 INTERSECT(1), //取交集 UNION(2), //取并集 XOR(3), //取异并集 REVERSE_DIFFERENCE(4), //取反转补集 REPLACE(5); //取后者区域代替前者 Op(int nativeInt) { this.nativeInt = nativeInt; } /** * @hide */ public final int nativeInt; }
代码示例如下:
public class RegionView extends View { private Paint mPaint; public RegionView(Context context) { this(context, null); } public RegionView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RegionView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } private void initPaint() { mPaint = new Paint(); mPaint.setColor(Color.GREEN); mPaint.setStrokeWidth(3); mPaint.setStyle(Paint.Style.STROKE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Path path1 = new Path(); Path path2 = new Path(); path1.addCircle(500, 500, 300, Path.Direction.CW); path2.addCircle(500, 800, 300, Path.Direction.CW); canvas.drawPath(path1, mPaint); canvas.drawPath(path2, mPaint); Region region1 = new Region(); Region region2 = new Region(); region1.setPath(path1, new Region(0, 0, 1500, 1500)); region2.setPath(path2, new Region(0, 0, 1500, 1500)); region1.op(region2, Region.Op.REPLACE); mPaint.setColor(Color.GREEN); mPaint.setStyle(Paint.Style.FILL); RegionIterator iterator = new RegionIterator(region1); Rect rect = new Rect(); while (iterator.next(rect)) { canvas.drawRect(rect, mPaint); } }}
各结果如下:
image
结尾
喜欢的朋友可以收藏点个赞哦。
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论