android path自动闭合,Android Path图形与逻辑运算

涉及知识

Path类型API描述添加路径addArc, addCircle, addOval, addPath, addRect,   addRoundRect, arcTo依次为添加圆弧、圆、椭圆、路径、矩形、圆角矩形、圆弧

移动起点moveTo移动起点位置,仅对之后路径产生影响

移动终点setLastPoint移动上一次的终点位置,对前后的路径都会产生影响

直线lineTo增加一条道指定点的直线

贝塞尔quadTo, cubicTo二阶、三阶贝塞尔曲线

闭合路径close路径终点连接到起点

逻辑运算opA\B(DIFFERENCE), A∩B(INTERSECT),   B\A(REVERSE_DIFFERENCE), A∪B(UNION), A⊕B(XOR)

替换路径set用新的路径替换当前路径

重置reset, rewind清除path使它为空,清除path但保留内部的数据结构

计算边界computeBounds计算路径的矩形边界

闭合方向Direction顺时针方向闭合Path(CW),逆时针方向闭合Path(CCW)

本来这章应该是PieChart的实战,可是我在编写的时候发现了一个设置背景图片的bug。作为一个强迫症(ಥ_ಥ),我只好引入了Path来解决这个bug,所以就有了这一篇内容。

一、什么是Path

官方描述:

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

我的理解:

Path由任意多条直线、二次贝塞尔或三次贝塞尔曲线组成,可以选择填充或者描边模式,可以使用它裁剪画布或者绘制文字。

二、添加路径

1、lineTo,moveTo

在之前的文章中,使用canvas的函数绘制过坐标系,这次使用path来绘制。

a、创建画笔

创建画笔并初始化

[代码]java代码:1

2

3

4

5

6

7

8//创建画笔

private Paint mPaint = new Paint();

private void initPaint(){

//初始化画笔

mPaint.setStyle(Paint.Style.FILL);//设置画笔类型

mPaint.setAntiAlias(true);//抗锯齿

}

b、绘制坐标轴

使用onSizeChanged方法,获取根据父布局等因素确认的View宽高

[代码]java代码:01

02

03

04

05

06

07

08

09

10//宽高

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;

}

把原点从左上角移动到画布中心,绘制原点与四个端点

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13private 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);

增加坐标轴与箭头的Path,在完成后使用canvas.drawPath一次进行绘制

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17mPaint.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);

可以看出moveTo方法,可以移动下一次增加path的起点,而lineTo中的参数,即为直线的终点。

2、addArc与arcTo方法区别addArc画一段圆弧

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

addArc

[代码]java代码:1

2

3

4

5

6

7

8r = 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

[代码]java代码:1

2

3

4

5//arcTo

mPath.moveTo(0,0);

mPath.arcTo(mRectF,-60,180);

//绘制Path

canvas.drawPath(mPath,mPaint);

可以看到arcTo多了一条从原点到圆弧起点的直线,而如果设置为mPath.arcTo(mRectF,-60,180,false);效果将和addArc相同。

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

继承ImageView,重写父类的onSizeChanged方法,获取View尺寸,之后根据View大小对图片进行压缩。

[代码]java代码:1

2

3

4

5

6

7

8@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的方法来实现圆角图片。

[代码]java代码:1

2

3

4

5

6

7@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方法中对图片的尺寸进行压缩

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20private 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的切割尺寸

[代码]java代码:1

2

3

4protected void size(){

length =   Math.min(mViewWidth,mViewHeight)/2;

rect = new Rect(-(int) length,   -(int) length, (int) length, (int) length);//绘制图片矩阵

}

现在就是发挥想象力的时候啦(^∇^*),来编写pathFigure()方法吧

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

[代码]java代码:1

2

3

4

5

6

7

8protected Path pathFigure(){

switch (modeFlag){

case CIRCLE:

mPath.addCircle(0,0,length,   Path.Direction.CW);//增加圆的path,顺时针闭合圆

break;

}

return mPath;

}

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

[代码]java代码:1

2

3

4

5

6

7

8

9private 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;

c、再增加一个扇形样式

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

[代码]java代码:1

2

3

4

5

6

7

8case 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;

四、逻辑运算

两条Path可通过多种逻辑运算进行结合,形成新的Path。

API如下:

[代码]java代码:1

2op(Path path, Path.Op op)

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

逻辑运算具有五种类型:方法描述DIFFERENCEB在A中的相对补集,即A减去A与B的交集

REVERSE_DIFFERENCEA在B中的相对补集合,即B减去B与A的交集

INTERSECTA与B的交集

UNIONA与B的合集

XORA与B的合集减去A与B的交集

使用Path.op方法再给圆角图片类,增加一种环形样式:

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16case 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);//异或获取环形

五、小结

本文介绍了Path的基本使用方法与逻辑运算,同时通过圆角图片的例子,进行了实战。使用Path方法,还可以增加更多有趣的图形,比如star,多边形,格子图等等。如果在阅读过程中,有任何疑问与问题,欢迎与我联系。

PS:示例中使用的方法,相对消耗内存,更合适的是设置反向填充来完成圆角图片的生成,FigureImageView为反向填充的方法,OldFigureImageView为示例中的方法

推荐:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值