# 自定义View——Path图形与逻辑运算

## 一、什么是Path

Path class 封装了由直线、二次、三次贝塞尔曲线构成的多重曲线几何路径。它可以用canvas.drawPath(path,paint)方法绘图，填充和线都可以（根据paint的样式），或者它可以用于在绘图路径上裁剪或者绘出文本。

## 二、添加路径

### 1、lineTo,moveTo

#### a、创建画笔

``//创建画笔 private Paint mPaint = new Paint();  private void initPaint(){     //初始化画笔     mPaint.setStyle(Paint.Style.FILL);//设置画笔类型     mPaint.setAntiAlias(true);//抗锯齿 } ``

#### b、绘制坐标轴

``//宽高 private int mWidth; private int mHeight;  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {     super.onSizeChanged(w, h, oldw, oldh);     mWidth = w;     mHeight = h; } ``

``private Path mPath = new Path();  canvas.translate(mWidth/2,mHeight/2);// 将画布坐标原点移动到中心位置 //绘制坐标原点 mPaint.setColor(Color.BLACK);//设置画笔颜色 mPaint.setStrokeWidth(10);//为了看得清楚,设置了较大的画笔宽度 canvas.drawPoint(0,0,mPaint); //绘制坐标轴4个断点 canvas.drawPoints(new float[]{         mWidth/2*0.8f,0         ,0,mHeight/2*0.8f         ,-mWidth/2*0.8f,0         ,0,-mHeight/2*0.8f},mPaint); ``

``mPaint.setStrokeWidth(1);//恢复画笔默认宽度 //x轴 mPath.moveTo(-mWidth/2*0.8f,0);//移动path起点到(-mWidth/2*0.8f,0) mPath.lineTo(mWidth/2*0.8f,0);//直线终点为(mWidth/2*0.8f,0) //y轴 mPath.moveTo(0,-mHeight/2*0.8f);//移动path起点到(0,-mHeight/2*0.8f) mPath.lineTo(0,mHeight/2*0.8f);//直线终点为(0,mHeight/2*0.8f) //x箭头 mPath.moveTo(mWidth/2*0.8f*0.95f,-mWidth/2*0.8f*0.05f); mPath.lineTo(mWidth/2*0.8f,0); mPath.lineTo(mWidth/2*0.8f*0.95f,mWidth/2*0.8f*0.05f); //y箭头 mPath.moveTo(mWidth/2*0.8f*0.05f,mHeight/2*0.8f-mWidth/2*0.8f*0.05f); mPath.lineTo(0,mHeight/2*0.8f); mPath.lineTo(-mWidth/2*0.8f*0.05f,mHeight/2*0.8f-mWidth/2*0.8f*0.05f); //绘制Path canvas.drawPath(mPath,mPaint); ``

arcTo 画一段圆弧，当上一次的终点与圆弧起点未连接时，可以设置是否连接这两点

``r = Math.min(mWidth,mHeight)*0.6f/2; mRectF.left = 0; mRectF.top = -r; mRectF.right = r; mRectF.bottom = 0; mPath.addArc(mRectF,-60,180); //绘制Path canvas.drawPath(mPath,mPaint); ``

``//arcTo mPath.moveTo(0,0); mPath.arcTo(mRectF,-60,180); //绘制Path canvas.drawPath(mPath,mPaint); ``

## 三、圆角图片以及更多形状图片

``@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {     super.onSizeChanged(w, h, oldw, oldh);     mViewWidth = w;     mViewHeight = h;     size();//切割尺寸计算     scaleBitmap();//压缩图片尺寸函数 } ``

onDraw 方法中进行样式绘制，在其中使用 clipPath 的方法来实现圆角图片。

``@Override protected void onDraw(Canvas canvas) {     canvas.translate(mViewWidth/2,mViewHeight/2);//将画布坐标原点移动到中心位置     canvas.clipPath(pathFigure(), Region.Op.INTERSECT);//切割     mPath.reset();     canvas.drawBitmap(b,rect,rect,mPaint); } ``

scaleBitmap 方法中对图片的尺寸进行压缩

``private void scaleBitmap(){     Drawable drawable = getDrawable();//获取图片     if (drawable == null) {         return;     }     if (getWidth() == 0 || getHeight() == 0) {         return;     }     if (!(drawable instanceof BitmapDrawable)) {         return;     }     b = ((BitmapDrawable) drawable).getBitmap();//获取bitmap     if (null == b) {         return;     }     float scaleWidth = (float) length/b.getWidth();     float scaleHeight = (float) length/b.getHeight();     matrix.postScale(scaleWidth,scaleHeight);//缩放矩阵     b=Bitmap.createBitmap(b,0,0,b.getWidth(),b.getHeight(),matrix,true);//压缩图片 } ``

size 方法中设置canvas的切割尺寸

``protected void size(){     length = Math.min(mViewWidth,mViewHeight)/2;     rect = new Rect(-(int) length, -(int) length, (int) length, (int) length);//绘制图片矩阵 } ``

#### a、先编写一个简单的圆形图片样式

``protected Path pathFigure(){     switch (modeFlag){         case CIRCLE:             mPath.addCircle(0,0,length, Path.Direction.CW);//增加圆的path，顺时针闭合圆             break;     }     return mPath; } ``

#### b、增加一个圆角图片样式

``private RectF rectF = new RectF();  case ROUNDRECT:             rectF.left = -length;             rectF.top = -length;             rectF.right = length;             rectF.bottom = length;             mPath.addRoundRect(rectF,radius,radius, Path.Direction.CW);//圆角矩形，radius为圆角的半径，顺时针闭合圆角矩形             break; ``

#### (PS:为了可以获得更多的图片面积，需要把圆心下移一个length的距离，半径扩大到之前的两倍)

``case SECTOR:     rectF.left = -length*2;     rectF.top = -length;     rectF.right = length*2;     rectF.bottom = length*3;     mPath.moveTo(0,length);     mPath.arcTo(rectF,angle,-angle*2-180);//绘制圆弧     break; ``

## 四、逻辑运算

API如下:

``op(Path path, Path.Op op) op(Path path1, Path path2, Path.Op op) ``

DIFFERENCE B在A中的相对补集，即A减去A与B的交集
REVERSE_DIFFERENCE A在B中的相对补集合，即B减去B与A的交集
INTERSECT A与B的交集
UNION A与B的合集
XOR A与B的合集减去A与B的交集

``case RING:     rectF.left = -length*2;     rectF.top = -length;     rectF.right = length*2;     rectF.bottom = length*3;     mPath1.moveTo(0,length);     mPath1.arcTo(rectF,angle,-angle*2-180);//较大的圆弧      rectF.left = -length/2;     rectF.top = length/2;     rectF.right = length/2;     rectF.bottom = length*3/2;     mPath2.moveTo(0,length);     mPath2.arcTo(rectF,angle,-angle*2-180);//较小的圆弧      mPath.op(mPath1,mPath2, Path.Op.XOR);//异或获取环形 ``

## 五、小结

GitHub: https://github.com/Idtk