Android动画 - PathMeasure打造不一样的动画

2,335 阅读5分钟

PathMeasures是什么

顾名思义,PathMeasure是一个用来测量Path的类

构造函数

构造函数方法描述
PathMeasure()创建一个空的PathMeasure对象。
PathMeasure(Path path, boolean forceClosed)创建与指定路径对象(已经创建并指定)关联的PathMeasure对象。

公共方法

返回值方法名称
floatgetLength()
booleangetMatrix(float distance, Matrix matrix, int flags)
booleangetPosTan(float distance, float[] pos, float[] tan)
booleangetSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
booleanisClosed()
booleannextContour()
voidsetPath(Path path, boolean forceClosed)

接下来分别介绍下以上的方法


1.构造函数

无参构造函数:
PathMeasure()

创建一个空的PathMeasure,要使用它来测量路径长度,或查找路径的位置和切线,需要调用setPath。一旦路径与测量对象相关联,Path进行了更改,需要重新调用setPath方法。

有参构造函数
PathMeasure(Path path, boolean forceClosed)

创建与指定路径对象关联的PathMeasure对象。现在,测量对象可以返回路径的长度以及路径上任何位置的位置和切线。同上,一旦路径与测量对象相关联,Path进行了更改,需要重新调用setPath方法。 forceClosed:如果为true,该路径也将被视为“闭合”。

forceClosed不会影响Path本身的状态。但是会影响测量结果。

下面我们举个例子:

    canvas.translate(mWidth/2,mHeight/2);

    Path path = new Path();
    path.lineTo(0,200);
    path.lineTo(200,200);
    path.lineTo(200,0);
    PathMeasure measure1 = new PathMeasure(path,false);
    PathMeasure measure2 = new PathMeasure(path,true);

    Log.e("TAG", "forceClosed=false---->"+measure1.getLength());
    Log.e("TAG", "forceClosed=true----->"+measure2.getLength());
    canvas.drawPath(path,mDeafultPaint);

log如下:

E/TAG: forceClosed=false---->600.0
E/TAG: forceClosed=true----->800.0

绘制的效果如下:

2.公共方法

getLength

返回当前Path的总长度;如果没有路径与此度量对象关联,则返回0。

isClosed

如果当前Path为close(),则返回true。

setPath

Path与PathMeasure进行关联。 主要讲一下以下几个方法:

nextContour
public boolean nextContour()

获取在路径中下一个轮廓,如果有下一个轮廓,则返回true,且PathMeasure切至下一个轮廓的数据;如果没有下一个轮廓则返回false。 我的理解一次moveTo增加一个轮廓。

getSegment
public boolean getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo)

给定起点和终点的距离,请返回中间的路段。如果段的长度为零,则返回false,否则返回true。startD和stopD固定取值范围(0,getLength())。如果startD> = stopD,则返回false(并保持dst不变)。如果startWithMoveTo为true,则以moveTo开头。

参数作用
startD开始截取的位置距离Path起点的距离
stopD结束截取的位置距离Path起点的距离
dst截取的Path会添加到dst中
startWithMoveTo起点是否启用moveTo

startD 和 stopD 的取值范围 0 <= startD < stopD <= getLength startWithMoveTo: 截取的片段的第一个点是否保持不变; 设置为true:保持截取的片段不变,添加至dst路径中; 设置为false:会将截取的片段的起始点移至dst路径中的最后一个点,让dst路径保持连续

举个例子:startWithMoveTo 为flase

canvas.translate(width/2,height/2);
Path mPath = new Path();
Path mDst = new Path();
PathMeasure mPathMeasure = new PathMeasure();
// 顺时针画 半径为400px的圆
mPath.addCircle(0,0, 400, Path.Direction.CW);
mPathMeasure.setPath(mPath, false);

// 画直线
mDst.moveTo(110, 0);
mDst.lineTo(200, 300);

// 截取 0.25 到 0.5 距离的圆弧放置dst中
mPathMeasure.getSegment(mPathMeasure.getLength() * 0.25f,
                mPathMeasure.getLength() * 0.5f,
                mDst,
                false);

canvas.drawPath(mDst, paint);

效果图如下:

startWithMoveTo 为true 效果图如下:

getPosTan
public boolean getPosTan(float distance, float pos[], float tan[]) 
参数作用
distance即需要的测量点与当前path起始位置的距离
pos测量点的坐标,pos[0]为x坐标,pos[1]为y坐标
tan测量点的正余弦值,tan[0]为cos,即余弦值或称为单位圆的x坐标;tan[1]为sin,即正弦值或称为单位圆的y坐标;

distance 取值范围:0<=distance<=getLength() A(x,y)原点为O,cos = OA/OB,sin = OA/AB

getMatrix
public boolean getMatrix(float distance, Matrix matrix, int flags)
参数作用
distance即需要的测量点与当前path起始位置的距离
matrix根据 falgs 封装好的matrix
flags规定哪些内容会存入到matrix中

flags 有POSITION_MATRIX_FLAG(位置) 和 ANGENT_MATRIX_FLAG(正切)两种 其实这个方法就相当于getPosTan的封装 matrix 的过程由 getMatrix 替我们做了,我们可以直接得到一个封装好到 matrix。

实战

加载动画(一)

效果图

主要利用PathMeasure的getSegment方法来截取路径,绘制该动画

思路

1.先勾勒出一个顺时针的空心圆,然后生成pathMeasure对象

// 勾勒空心圆
path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
// 生成pathMeasure对象
pathMeasure.setPath(path, true);

2.截取的开始值和结束值

stop = mAnimatorValue * mLength;
start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));

mAnimatorValue 的取值为(0,1) ,当mAnimatorValue为0或1时,两个值相等。

3.截取路径后绘制路径

pathMeasure.getSegment(start, stop, dst, true);
canvas.drawPath(dst, paint);

完整代码地址: 有用记得点颗小星星


加载动画化(二)

效果图

思路

主要利用getPosTan 获取测量点的坐标和正余弦值,控制箭头的方法和位置 1.先勾勒出一个顺时针的空心圆,然后生成pathMeasure对象

// 勾勒空心圆
path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
// 生成pathMeasure对象
pathMeasure.setPath(path, true);

2.获取绘制点的测量坐标和正余弦值,根据tan[0],tan[1]来计算箭头旋转的角度。

measure.getPosTan(measure.getLength() * mAnimatorValue, pos, tan);
float angle = (float) (Math.atan2(tan[1], tan[0]) * 180 / Math.PI);

mAnimatorValue 的取值为(0,1) ,当mAnimatorValue为0或1时,两个值相等。 angle计算方式自行查找,数学知识。

3.用Matrix对bitmap进行旋转和平移

mMatrix.postRotate(angle,mBitmap.getWidth()/2,mBitmap.getHeight()/2);
mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2,pos[1] - mBitmap.getHeight() / 2);

4.绘制bitmap

canvas.drawBitmap(mBitmap,mMatrix,mPaint);

完整代码地址: 有用记得点颗小星星


往期文章地址

Android动画 - 仿花束直播加载动画

Android动画 - 仿58同城加载动画

Android动画 - 仿抖音加载动画