300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > android自定义控件-Path的进阶使用方法

android自定义控件-Path的进阶使用方法

时间:2020-09-14 15:00:14

相关推荐

android自定义控件-Path的进阶使用方法

代码 github 地址

点开代码能更好理解文章中的内容呦

/ananananzhuo-blog/CustomViewDemo.git

Path 中的方法

1、重置 path 方法

publicvoidreset()

2、将画笔移动到指定位置(起始位置)

这个方法的 x,y 坐标是绝对坐标

publicvoidmoveTo(floatx,floaty)

3、将画笔移动到指定位置(起始位置)

和 2 中不同,这个方法中的 x,y 坐标是相对坐标

publicvoidrMoveTo(floatdx,floatdy)

4、与 2 相对应,移动 path

绝对坐标

publicvoidlineTo(floatx,floaty)

5、与 3 相对应,移动 path

相对坐标

publicvoidrLineTo(floatdx,floatdy)

6、二阶贝塞尔曲线

绝对坐标

x1,y1:贝塞尔曲线的控制点

x2,y2:贝塞尔曲线的终点坐标

publicvoidquadTo(floatx1,floaty1,floatx2,floaty2)

7、二阶贝塞尔曲线

相对坐标

publicvoidrQuadTo(floatdx1,floatdy1,floatdx2,floatdy2)

8、三阶贝塞尔曲线

绝对坐标

x1、y1:三阶贝塞尔曲线第一控制点

x2、y2:三阶贝塞尔曲线第二个控制点

x3、y3:三阶贝塞尔曲线的终点

publicvoidcubicTo(floatx1,floaty1,floatx2,floaty2,floatx3,floaty3)

9、三阶贝塞尔曲线

相对坐标

publicvoidrCubicTo(floatx1,floaty1,floatx2,floaty2,floatx3,floaty3)

10、画弧线

publicvoidarcTo(RectFoval,floatstartAngle,floatsweepAngle,booleanforceMoveTo)

代码示例

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)canvas?.apply{path.reset()paint.color=Color.YELLOWcanvas.drawCircle(250f,250f,150f,paint)paint.color=Color.REDvalovalRectf=RectF(100f,100f,400f,400f)path.arcTo(ovalRectf,0f,120f)path.close()drawPath(path,paint)}}

实现效果: 红色部分的弧形就是我们要实现的效果,黄色部分是我们的弧形对应的整圆只起到一个参考的作用

11、将 path 进行偏移

偏移结果写到 dst 中

publicvoidoffset(floatdx,floatdy,@NullablePathdst)

publicvoidoffset(floatdx,floatdy)

12、结束 path,将起点终点相连

publicvoidclose()

两个 path 之间的算法(Path.Op)

//这个方法是Path的成员方法publicbooleanop(Pathpath,Opop)

下面表格是对 op 属性的说明

代码示例(分支名:path)

//代码所属类:PathOpView所属分支pathoverridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()path2.reset()canvas?.apply{path1.addCircle(200f,200f,radius1,Direction.CW)path2.addCircle(400f,400f,radius2,Direction.CW)path1.op(path2,ops)path1.close()path2.close()canvas.drawPath(path1,paint1)//canvas.drawPath(path2,paint2)//这里一定不要再绘制path2了,因为path1.op(path2,ops)的存在,path2默认就会被绘制}}

本示例中可以通过拖动 Seekbar 改变两个圆的大小,通过点击按钮的弹窗列表框选择不同的 Path.Ops 属性查看效果

效果图:

Path.Direction 方向

Path 的多个绘制方法有 Path.Direction 形参的

1、 PathDirectionCCW 逆时针

示例代码

path1.addRect(rect,W)

2、 PathDirectionCW 顺时针

示例代码

path1.addRect(rect,Path.Direction.CW)

Path 填充-FillType

Path 填充

FillType 是个枚举,里面有四种类型

publicenumFillType{WINDING(0),EVEN_ODD(1),INVERSE_WINDING(2),INVERSE_EVEN_ODD(3);}

1、WINDING

判断 path 区域是否需要被填充的方式:从该区域向外画一条射线,因为 Path 是有方向的(顺时针和逆时针 Path.Direction)。我们假设顺时针为正,逆时针为负,如果最终得到的值的绝对值大于 0 该区域就是内部区域应该被填充,如果==0 该区域为外部区域不可以被填充。所以当与射线相交的边框方向相反(一个顺时针一个逆时针)的时候就是正负得 0,该区域是外部区域不可以被填充

方向相同

代码:

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.WINDINGdrawPath(path1,paint)}}

代码实现效果

方向相反

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,W)path1.fillType=Path.FillType.WINDINGdrawPath(path1,paint)}}

代码实现效果

2、INVERSE_WINDING

方向相同

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.INVERSE_WINDINGdrawPath(path1,paint)}}

代码实现效果展示

方向相反

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,W)path1.fillType=Path.FillType.INVERSE_WINDINGdrawPath(path1,paint)}}

代码效果展示

3、EVEN_ODD

与 WINDING 相同,EVEN_ODD 也是使用画射线的方式确定是否为内部可填充区域。如果射线与 path 相交的交点数为偶数则属于外部区域,不需要被填充。如果是奇数则是内部区域,需要被填充。 效果图展示:

代码展示:

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.EVEN_ODDdrawPath(path1,paint)}}

代码效果展示

4、INVERSE_EVEN_ODD

该放手与 EVEN_ODD 被填充的区域刚好相反 代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.INVERSE_EVEN_ODDdrawPath(path1,paint)}}

代码效果展示

代码示例(分支名:path)

//代码所属类:PathOpView所属分支pathoverridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()path2.reset()canvas?.apply{path1.addCircle(200f,200f,radius1,Direction.CW)path2.addCircle(400f,400f,radius2,Direction.CW)path1.op(path2,ops)path1.close()path2.close()canvas.drawPath(path1,paint1)//canvas.drawPath(path2,paint2)//这里一定不要再绘制path2了,因为path1.op(path2,ops)的存在,path2默认就会被绘制}}

本示例中可以通过拖动 Seekbar 改变两个圆的大小,通过点击按钮的弹窗列表框选择不同的 Path.Ops 属性查看效果

效果图:

Path.Direction 方向

Path 的多个绘制方法有 Path.Direction 形参的

1、 PathDirectionCCW 逆时针

示例代码

path1.addRect(rect,W)

2、 PathDirectionCW 顺时针

示例代码

path1.addRect(rect,Path.Direction.CW)

Path 填充-FillType

Path 填充

FillType 是个枚举,里面有四种类型

publicenumFillType{WINDING(0),EVEN_ODD(1),INVERSE_WINDING(2),INVERSE_EVEN_ODD(3);}

1、WINDING

判断 path 区域是否需要被填充的方式:从该区域向外画一条射线,因为 Path 是有方向的(顺时针和逆时针 Path.Direction)。我们假设顺时针为正,逆时针为负,如果最终得到的值的绝对值大于 0 该区域就是内部区域应该被填充,如果==0 该区域为外部区域不可以被填充。所以当与射线相交的边框方向相反(一个顺时针一个逆时针)的时候就是正负得 0,该区域是外部区域不可以被填充

方向相同

代码:

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.WINDINGdrawPath(path1,paint)}}

代码实现效果

方向相反

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,W)path1.fillType=Path.FillType.WINDINGdrawPath(path1,paint)}}

代码实现效果

2、INVERSE_WINDING

方向相同

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.INVERSE_WINDINGdrawPath(path1,paint)}}

代码实现效果展示

方向相反

代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,W)path1.fillType=Path.FillType.INVERSE_WINDINGdrawPath(path1,paint)}}

代码效果展示

3、EVEN_ODD

与 WINDING 相同,EVEN_ODD 也是使用画射线的方式确定是否为内部可填充区域。如果射线与 path 相交的交点数为偶数则属于外部区域,不需要被填充。如果是奇数则是内部区域,需要被填充。 效果图展示:

代码展示:

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.EVEN_ODDdrawPath(path1,paint)}}

代码效果展示

4、INVERSE_EVEN_ODD

该放手与 EVEN_ODD 被填充的区域刚好相反 代码展示

overridefunonDraw(canvas:Canvas?){super.onDraw(canvas)path1.reset()canvas?.apply{path1.addCircle(200f,200f,100f,Path.Direction.CW)path1.addCircle(300f,300f,150f,Path.Direction.CW)path1.fillType=Path.FillType.INVERSE_EVEN_ODDdrawPath(path1,paint)}}

代码效果展示

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。