前言:
PathMeasure:见名知意,是一个Path的测绘类,那测绘Path干嘛用呢?先来看一下一个效果图
如果要实现上图的动画特效,PathMeasure可以一步到位的实现。看到这里是不是很兴奋呢?以前看到这种特效,不了解的都以为是gif或者是帧动画呢。现在让我们揭露PathMeasure的神秘面纱(ps:文章底部有SearchView源码)
PathMeasure
构造函数
方法名 | 说明 |
---|---|
PathMeasure() | 实例化一个空的PathMeasure 使用该方法,必须要调用setPath() |
PathMeasure(Path path,boolean foreClosed) | 实例化一个关联Path的PathMeasure |
公有方法
返回值 | 方法名 | 说明 |
---|---|---|
float | getLength() | 得到path中所有点测绘的长度 |
boolean | getMatrix(float distance,Matrix matrix,int flags) | 得到一定长度的Matrix |
boolean | getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo) | 得到指定长度的Path(),类似裁剪 |
boolean | isClosed() | 返回true,表明测量的长度有加上起始点到终点的距离 |
boolean | nextContour() | 移动到下一条路径 |
boolean | getPotTan() | 得到指定长度的终点坐标和正切值()终点坐标和线段的) |
void | setPath() | 关联一个Path |
码一下,进一步认知
两个参数的构造函数中,其中foreClosed参数值只会影响测量Path的结果:
true: 测量Path的路径会加上起点到结束点的距离
false:不加上起点到结束点的距离
fun drawDemo(canvas: Canvas?){
val path = Path()
path.lineTo(0f,-200f)
path.lineTo(200f,-200f)//每一边长为200*3=600
path.lineTo(200f,0f)
canvas?.drawPath(path,mPaint)
val pathMeasure = PathMeasure(path,false)
val pathMeasure1 = PathMeasure(path, true)
LogUtil.i("forceClosed为false"+pathMeasure.length)
LogUtil.i("forceClosed为true"+pathMeasure1.length)
}
效果图:
log打印结果:
(CoordinateView.kt:52)--forceClosed为false---600.0
(CoordinateView.kt:53)--forceClosed为true---800.0
经过代码测试我们可以知道:
forceClosed的状态仅仅只能改变PathMeasure的测量值,而Path.close()才是影响绘画的结果。
nextContour()移动到下一条路径?什么鬼听不懂,好吧,让我们从实践出发,去了解所谓的移动到下一条路径
fun drawDemo(canvas: Canvas?){
val path = Path()
path.lineTo(0f,-200f)
path.lineTo(300f,-200f) //总长度500
path.addRect(-100f,-100f,100f,100f,Path.Direction.CW)//总长度800
canvas?.drawPath(path,mPaint)
val pathMeasure = PathMeasure(path,false)
LogUtil.i("未nextContour的测量长度: "+pathMeasure.length)
val nextContour = pathMeasure.nextContour()
LogUtil.i("nextContour状态: "+nextContour+"测量长度: "+pathMeasure.length)
}
效果图:
Log信息
(CoordinateView.kt:50)--未nextContour的测量长度: 500.0
(CoordinateView.kt:52)--nextContour状态: true测量长度: 800.0
可以得出的是在Path对象中,如果存在两条路径,则nextConTour()返回true,并且pathMeasure测量移动指定的路径。如果不存在,就不会执行nextContour()以下代码
getSegment(float startD,float stopD,Path dst,boolean startWidthMoveTo)是涉及特效中离不来的方法,可以理解裁剪Path中的指定路径并得到。如果路径长度为0,返回false,否则返回true,startD、stopD是指定从那个长度到某个长度,
- 在dst中已经存在path,为了连贯性截取 (startWithMoveTo=false)的起点会自动连接dst存在path的末点,如果不存在有值建议startWithMoveTo=true,不然会出乎你的意外的。
fun drawDemo(canvas: Canvas?){
val path = Path()
path.addRect(-100f,-100f,100f,100f,Path.Direction.CW)//正方形path
val pathMeasure = PathMeasure(path,false)
val dst = Path()
pathMeasure.getSegment(0f,400f,dst,true)//截取从0到400的长度
canvas?.drawPath(dst,mPaint)
}
fun drawDemo(canvas: Canvas?){
val path = Path()
path.addRect(-100f,-100f,100f,100f,Path.Direction.CW)//正方形path
val pathMeasure = PathMeasure(path,false)
val dst = Path()
dst.lineTo(-200f,-100f)
pathMeasure.getSegment(0f,400f,dst,false)//截取从0到400的长度
canvas?.drawPath(dst,mPaint)
}
通过不断的改变startD的值,可以完成一个绘画圆环的过程,而改变startD值可以采用属性动画,类似的文章开头的特效也是采用此思路
getPosTan(float distance,pos,tan) 是获取指定distance位置的点坐标和tan值(获取角度Math.toDegrees(Math.atan2(tan[1].toDouble(),tan[0].toDouble()))))
fun drawDemo(canvas: Canvas?){
val path = Path()
path.addCircle(0f,0f,100f,Path.Direction.CW)//正方形path
val pathMeasure = PathMeasure(path,false)
canvas?.drawPath(path,mPaint)
val pos = FloatArray(2)
val tan = FloatArray(2)
val posTan = pathMeasure.getPosTan(34f, pos, tan)
LogUtil.i("指定位置的坐标x "+pos[0]+"y "+pos[1])
LogUtil.i("指定位置的tan值 "+Math.toDegrees(Math.atan2(tan[1].toDouble(),tan[0].toDouble())))
}
log信息
(CoordinateView.kt:51)--指定位置的坐标x 94.78189y 31.880926
(CoordinateView.kt:52)--指定位置的tan值 108.59092909967784
总结
PathMeasure常用的方法到这里已经一一详解,接下来我们就用PathMeasure去实践炫酷的SearchView。android自定义view--SearchView