package com.mcxtzhang.cstviewdemo.outpututils;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* 介绍:一个自定义View Path动画的工具类
* <p>
* 一个SourcePath 内含多段Path,循环取出每段Path,并做一个动画,
* <p>
* 默认动画时间1500ms,无限循环
* 可以通过构造函数修改这两个参数
* <p>
* 对外暴露 startAnim() 和 stopAnim()两个方法
* 作者:zhangxutong
* 邮箱:zhangxutong@imcoming.com
* 时间: 2016/11/2.
*/
public class PathAnimHelper {
private static final String TAG = "zxt/PathAnimHelper";
private static final long mDefaultAnimTime = 1500;//默认动画总时间
private View mView;//执行动画的View
private Path mSourcePath;//源Path
private Path mAnimPath;//用于绘制动画的Path
private long mAnimTime;//动画一共的时间
private boolean mIsInfinite;//是否无限循环
private ValueAnimator mAnimator;//动画对象
/**
* INIT FUNC
**/
public PathAnimHelper(View view, Path sourcePath, Path animPath) {
this(view, sourcePath, animPath, mDefaultAnimTime, true);
}
public PathAnimHelper(View view, Path sourcePath, Path animPath, long animTime, boolean isInfinite) {
if (view == null || sourcePath == null || animPath == null) {
Log.e(TAG, "PathAnimHelper init error: view 、sourcePath、animPath can not be null");
return;
}
mView = view;
mSourcePath = sourcePath;
mAnimPath = animPath;
mAnimTime = animTime;
mIsInfinite = isInfinite;
}
/**
* GET SET FUNC
**/
public View getView() {
return mView;
}
public PathAnimHelper setView(View view) {
mView = view;
return this;
}
public Path getSourcePath() {
return mSourcePath;
}
public PathAnimHelper setSourcePath(Path sourcePath) {
mSourcePath = sourcePath;
return this;
}
public Path getAnimPath() {
return mAnimPath;
}
public PathAnimHelper setAnimPath(Path animPath) {
mAnimPath = animPath;
return this;
}
public long getAnimTime() {
return mAnimTime;
}
public PathAnimHelper setAnimTime(long animTime) {
mAnimTime = animTime;
return this;
}
public boolean isInfinite() {
return mIsInfinite;
}
public PathAnimHelper setInfinite(boolean infinite) {
mIsInfinite = infinite;
return this;
}
public ValueAnimator getAnimator() {
return mAnimator;
}
public PathAnimHelper setAnimator(ValueAnimator animator) {
mAnimator = animator;
return this;
}
/**
* 执行动画
*/
public void startAnim() {
startAnim(mView, mSourcePath, mAnimPath, mAnimTime, mIsInfinite);
}
/**
* 一个SourcePath 内含多段Path,循环取出每段Path,并做一个动画
* 自定义动画的总时间
* 和是否循环
*
* @param view 需要做动画的自定义View
* @param sourcePath 源Path
* @param animPath 自定义View用这个Path做动画
* @param totalDuaration 动画一共的时间
* @param isInfinite 是否无限循环
*/
private void startAnim(View view, Path sourcePath, Path animPath, long totalDuaration, boolean isInfinite) {
if (view == null || sourcePath == null || animPath == null) {
return;
}
PathMeasure pathMeasure = new PathMeasure();
//pathMeasure.setPath(sourcePath, false);
//先重置一下需要显示动画的path
animPath.reset();
animPath.lineTo(0, 0);
pathMeasure.setPath(sourcePath, false);
//这里仅仅是为了 计算一下每一段的duration
int count = 0;
while (pathMeasure.getLength() != 0) {
pathMeasure.nextContour();
count++;
}
//经过上面这段计算duration代码的折腾 需要重新初始化pathMeasure
pathMeasure.setPath(sourcePath, false);
loopAnim(view, sourcePath, animPath, totalDuaration, pathMeasure, totalDuaration / count, isInfinite);
}
/**
* 循环取出每一段path ,并执行动画
*
* @param animPath 自定义View用这个Path做动画
* @param pathMeasure 用于测量的PathMeasure
*/
private void loopAnim(final View view, final Path sourcePath, final Path animPath, final long totalDuaration, final PathMeasure pathMeasure, final long duration, final boolean isInfinite) {
//动画正在运行的话,先stop吧。万一有人要使用新动画呢,(正经用户不会这么用。)
stopAnim();
mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.setDuration(duration);
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//Log.i("TAG", "onAnimationUpdate");
float value = (float) animation.getAnimatedValue();
//获取一个段落
pathMeasure.getSegment(0, pathMeasure.getLength() * value, animPath, true);
//通知View刷新自己
view.invalidate();
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationRepeat(Animator animation) {
//Log.w("TAG", "onAnimationRepeat: ");
//每段path走完后,要补一下 某些情况会出现 animPath不满的情况
pathMeasure.getSegment(0, pathMeasure.getLength(), animPath, true);
//绘制完一条Path之后,再绘制下一条
pathMeasure.nextContour();
//长度为0 说明一次循环结束
if (pathMeasure.getLength() == 0) {
if (isInfinite) {//如果需要循环动画
animPath.reset();
animPath.lineTo(0, 0);
pathMeasure.setPath(sourcePath, false);
} else {//不需要就停止(因为repeat是无限 需要手动停止)
animation.end();
}
}
}
@Override
public void onAnimationEnd(Animator animation) {
//Log.e("TAG", "onAnimationEnd: ");
}
});
mAnimator.start();
}
/**
* 停止动画
*/
public void stopAnim() {
//Log.e("TAG", "stopAnim: ");
if (null != mAnimator && mAnimator.isRunning()) {
mAnimator.end();
//Log.e("TAG", "true stopAnim: ");
}
}
}