动画效果如下:
一、PathMeasure使用
PathMeasure类有两个构造方法,一个带参数,一个不带参数.
PathMeasure()
PathMeasure(Pathpath, 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();
booleangetSegment (floatstartD,floatstopD, Path dst,booleanstartWithMoveTo)
用于截取整个Path的片段,通过参数startD和stopD来控制截取的长度,并将截取的Path保存到dst中
二.Loading动画制作
使用ValueAnimator的ofFloat(0,1)方法,监听从0,1的变化.具体动画代码如下:
publicclassLoadingViewextendsView
{
privatestaticfinalintDRAW_CIRCLE =10001;
privatestaticfinalintROTATE_TRIANGLE =10002;
privatePath mPath;
privatePaint mPaint;
privatePathMeasure mPathMeasure;
privatefloatmAnimatorValue;
privatePath mDst;
privatefloatmLength;
privateintmCurrentState =0;//当前的状态
privatebooleanflag;
publicLoadingView(Context context)
{
super(context);
}
publicLoadingView(Context context, AttributeSet attrs)
{
super(context, attrs);
mPaint =newPaint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLACK);
mPath =newPath();
mPath.addCircle(400,400,100, Path.Direction.CW);
mPathMeasure =newPathMeasure();
mPathMeasure.setPath(mPath,true);
mLength = mPathMeasure.getLength();
mDst =newPath();
mCurrentState = DRAW_CIRCLE;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
valueAnimator.addUpdateListener(newValueAnimator.AnimatorUpdateListener()
{
@Override
publicvoidonAnimationUpdate(ValueAnimator valueAnimator)
{
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.start();
valueAnimator.addListener(newAnimator.AnimatorListener()
{
@Override
publicvoidonAnimationStart(Animator animator)
{
}
@Override
publicvoidonAnimationEnd(Animator animator)
{
}
@Override
publicvoidonAnimationCancel(Animator animator)
{
}
@Override
publicvoidonAnimationRepeat(Animator animator)
{
switch(mCurrentState){
caseDRAW_CIRCLE:
mCurrentState = ROTATE_TRIANGLE;
break;
caseROTATE_TRIANGLE:
mCurrentState = DRAW_CIRCLE;
break;
}
Log.e("mCurrentState",mCurrentState +"");
}
});
}
publicLoadingView(Context context, AttributeSet attrs,intdefStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
protectedvoidonDraw(Canvas canvas)
{
mDst.reset();
mDst.lineTo(0,0);
switch(mCurrentState){
caseDRAW_CIRCLE:
floatstop = mLength*mAnimatorValue;
mPathMeasure.getSegment(0,stop,mDst,true);
canvas.drawPath(mDst,mPaint);
break;
caseROTATE_TRIANGLE:
canvas.save();
floatstart = mLength*mAnimatorValue;
mPathMeasure.getSegment(start,mLength,mDst,true);
canvas.drawPath(mDst,mPaint);
break;
}
}
}