PathMeasure 是针对Path的测量类,它可以测量Path的长度、某点的坐标、正切值等。api中提供了两个构造方法,这里我们来看带参数的构造方法
public PathMeasure(Path path, boolean forceClosed) {
// The native implementation does not copy the path, prevent it from being GC'd
mPath = path;
native_instance = native_create(path != null ? path.readOnlyNI() : 0,
forceClosed);
}
path表示需要进行测量的对象,forceClosed表示在测量过程中,是否路径考虑闭合的状况,传递true值表示不论是否调用path.close()方法,都认为是闭合状态。
public float getLength() {
return native_getLength(native_instance);
}
表示获取当前path的长度。
public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) {
float length = getLength();
if (startD < 0) {
startD = 0;
}
if (stopD > length) {
stopD = length;
}
if (startD >= stopD) {
return false;
}
return native_getSegment(native_instance, startD, stopD, dst.mutateNI(), startWithMoveTo);
}
表示获取path中的某一段长度,startD表示起始值,stopD表示测量终点值,dst为测量后的path对象,startWithMoveTo表示是否移动至path起点并连线,看一下示例
红色区域是绘制了两个边长为200的矩形,我们分别对两个红色矩形测量200至600范围的path,上方的红色矩形在测量中startWithMoveTo参数传递了true,下方的则传递了false,可以很明显的观察到传递false时,将path范围为200的点与我们的画布起始点进行了连线,为true时则不会。
public boolean nextContour() {
return native_nextContour(native_instance);
}
如果path为多条互不连接的曲线构成,那么在测量过程中,如果想要测量下一个path的相关数据,调用该方法,则会顺沿到下一个path。
public boolean getPosTan(float distance, float pos[], float tan[]) {
if (pos != null && pos.length < 2 ||
tan != null && tan.length < 2) {
throw new ArrayIndexOutOfBoundsException();
}
return native_getPosTan(native_instance, distance, pos, tan);
}
测量距离path起始点的长度distance,pos、tan都是长度为2的数组,pos[0]表示x坐标,pos[1]表示y坐标,tan[0]是邻边边长,tan[1]是对边边长,通过Math.atan2(tan[1], tan[0])*180.0/Math.PI 可以得到正切角的弧度值。
下面我们做一个简单的示例,效果图如下:
重点在于getPosTan()方法的使用,该效果实际是对纸飞机进行平移和旋转操作,在对圆path的测量过程中,获取每一个路径的坐标以及正切值,坐标就是飞机的平移坐标,而正切值转换为角度值,就是飞机的旋转角度,主要实现onDraw()方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);
canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight(), linePaint);
canvas.translate(getWidth() / 2, getHeight() / 2);
path.reset();
path.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path, paint);
PathMeasure measure = new PathMeasure();
measure.setPath(path, false);
speed += 0.004;
if (speed > 1) {
speed = 0;
}
//这里对圆path进行测量
measure.getPosTan(measure.getLength() * speed, pos, tan);
//计算当前角度
double degree = Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI;
matrix.reset();
//旋转飞机
matrix.postRotate((float) degree,bitmap.getWidth()/2,bitmap.getHeight()/2);
//平移飞机
matrix.postTranslate(pos[0]-bitmap.getWidth()/2,pos[1]-bitmap.getHeight()/2);
canvas.drawBitmap(bitmap,matrix,paint);
invalidate();
}
这里我们通过speed对象来实时测量measure.getLength() * speed这一段路径值,并实时计算相应的坐标及角度,不断的对纸飞机进行旋转和平移操作即可。