动画效果如下:
一、PathMeasure使用
PathMeasure类有两个构造方法,一个带参数,一个不带参数.
PathMeasure()
PathMeasure(Path path, boolean forceClosed) 官方解释如下:
Create a PathMeasure object associated with the specified path object (already created and specified). The measure object can now return the path's length, and the position and tangent of any position along the path. Note that once a path is associated with the measure object, it is undefined if the path is subsequently modified and the the measure object is used. If the path is modified, you must call setPath with the path.
使用PathMeasure和path进行关联,可以追踪Path路径点的坐标,获取Path的长度.
API
getLength();
PathMeasure.getLength()其作用就是获取计算的路径长度。
getSegment();
boolean getSegment (float startD, float stopD, Path dst, boolean startWithMoveTo)
用于截取整个Path的片段,通过参数startD和stopD来控制截取的长度,并将截取的Path保存到dst中
二.Loading动画制作
使用ValueAnimator的ofFloat(0,1)方法,监听从0,1的变化.具体动画代码如下:
public class LoadingView extends View
{
private static final int DRAW_CIRCLE = 10001;
private static final int ROTATE_TRIANGLE = 10002;
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
private int mCurrentState = 0; //当前的状态
private boolean flag;
public LoadingView(Context context)
{
super(context);
}
public LoadingView(Context context, AttributeSet attrs)
{
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLACK);
mPath = new Path();
mPath.addCircle(400,400,100, Path.Direction.CW);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mPath,true);
mLength = mPathMeasure.getLength();
mDst = new Path();
mCurrentState = DRAW_CIRCLE;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
{
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.start();
valueAnimator.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animator)
{
}
@Override
public void onAnimationEnd(Animator animator)
{
}
@Override
public void onAnimationCancel(Animator animator)
{
}
@Override
public void onAnimationRepeat(Animator animator)
{
switch (mCurrentState){
case DRAW_CIRCLE:
mCurrentState = ROTATE_TRIANGLE;
break;
case ROTATE_TRIANGLE:
mCurrentState = DRAW_CIRCLE;
break;
}
Log.e("mCurrentState" ,mCurrentState + "");
}
});
}
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas)
{
mDst.reset();
mDst.lineTo(0,0);
switch (mCurrentState){
case DRAW_CIRCLE:
float stop = mLength*mAnimatorValue;
mPathMeasure.getSegment(0,stop,mDst,true);
canvas.drawPath(mDst,mPaint);
break;
case ROTATE_TRIANGLE:
canvas.save();
float start = mLength*mAnimatorValue;
mPathMeasure.getSegment(start,mLength,mDst,true);
canvas.drawPath(mDst,mPaint);
break;
}
}
}