
公式
关于贝塞尔曲线的定义大家可以看贝塞尔曲线的百度百科
-
线性公式
线性公式
-
二次方公式
二次方公式
-
三次方公式
三次方公式
代码的实现
- pathPoint常量
首先我们path绘制实际有三种,moveTo,Line和贝塞尔曲线Cubic,所以pathPoint主要是定义指令类型和坐标
public class PathPoint {
//指令类型
public static final int MOVE = 0;
public static final int LINE = 1;
public static final int CUBIC = 2;
int mOperation;
//坐标
float mX, mY;
float mControl0x, mControl0y, mControl1x, mControl1y;
public PathPoint(int operation, float x, float y) {
mOperation = operation;
this.mX = x;
this.mY = y;
}
public PathPoint(int operation, int c0x, int c0y, int c1x, int c1y, int x, int y) {
mOperation = operation;
this.mX = x;
this.mY = y;
this.mControl0x = c0x;
this.mControl0y = c0y;
this.mControl1x = c1x;
this.mControl1y = c1y;
}
}
- CustomPath build设计模式实现参数封装
public class CustomPath {
private List<PathPoint> mPathPoints;
private View mView;
private int mDuration;
private TimeInterpolator mInterpolator;
private CustomPath() {
}
public CustomPath(List<PathPoint> pathPoints,int duration, TimeInterpolator interpolator) {
this.mPathPoints = pathPoints;
this.mDuration = duration;
this.mInterpolator = interpolator;
}
public void moveTo(float x, float y) {
mPathPoints.add(new PathPoint(PathPoint.MOVE, x, y));
}
public void cubicTo(int c0x, int c0y, int c1x, int c1y, int x, int y) {
mPathPoints.add(new PathPoint(PathPoint.CUBIC, c0x, c0y, c1x, c1y, x, y));
}
public void lineTo(float x, float y) {
mPathPoints.add(new PathPoint(PathPoint.LINE, x, y));
}
public void setDuration(int duration) {
this.mDuration = duration;
}
public void setTimeInterpolator(TimeInterpolator interpolator) {
this.mInterpolator = interpolator;
}
public void startAnimation(View v) {
this.mView = v;
ObjectAnimator animator = ObjectAnimator.ofObject(this, "customAnimation", new PathEvalutor(), mPathPoints.toArray());
animator.setDuration(mDuration);
animator.setInterpolator(mInterpolator);
animator.start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (beizeAnimationEnd != null) {
beizeAnimationEnd.animationEnd(animation);
}
}
});
}
public void setCustomAnimation(PathPoint pathPoint) {
mView.setTranslationX(pathPoint.mX);
mView.setTranslationY(pathPoint.mY);
}
public static class Builder {
private List<PathPoint> mPathPoints;
private int mDuration;
private TimeInterpolator mInterpolator;
public Builder() {
mPathPoints = new ArrayList<>();
mDuration = 250;
mInterpolator = new LinearInterpolator();
}
public Builder moveTo(float x, float y) {
mPathPoints.add(new PathPoint(PathPoint.MOVE, x, y));
return this;
}
public Builder cubicTo(int c0x, int c0y, int c1x, int c1y, int x, int y) {
mPathPoints.add(new PathPoint(PathPoint.CUBIC, c0x, c0y, c1x, c1y, x, y));
return this;
}
public Builder lineTo(float x, float y) {
mPathPoints.add(new PathPoint(PathPoint.LINE, x, y));
return this;
}
public Builder setDuration(int duration) {
this.mDuration = duration;
return this;
}
public Builder setTimeInterpolator(TimeInterpolator interpolator) {
this.mInterpolator = interpolator;
return this;
}
public CustomPath build() {
return new CustomPath(mPathPoints, mDuration, mInterpolator);
}
}
//动画结束
public interface BeizeAnimationEnd {
public void animationEnd(Animator animation);
}
private BeizeAnimationEnd beizeAnimationEnd;
public void addBeizeAnimationEnd(BeizeAnimationEnd beizeAnimationEnd) {
this.beizeAnimationEnd = beizeAnimationEnd;
}
}
主要思路:1、我们可能会有多个指令类型一起执行,所以我们可以将所有的指令类型封装到一个集合中
2、执行动画使用属性动画ObjectAnimator.ofObject来执行
3、
ObjectAnimator animator = ObjectAnimator.ofObject(this, "customAnimation", new PathEvalutor(), mPathPoints.toArray());
customAnimation可以是任何名字,heihei也可以对应的是setHeihei。
- PathEvalutor源码
public class PathEvalutor implements TypeEvaluator<PathPoint> {
@Override
public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
float x, y;
if (endValue.mOperation == PathPoint.CUBIC) {//贝塞尔曲线
float oneMinusT = 1 - t;
x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
3 * oneMinusT * oneMinusT * t * endValue.mControl0x +
3 * oneMinusT * t * t * endValue.mControl1x +
t * t * t * endValue.mX;
y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
3 * oneMinusT * oneMinusT * t * endValue.mControl0y +
3 * oneMinusT * t * t * endValue.mControl1y +
t * t * t * endValue.mY;
} else if (endValue.mOperation == PathPoint.LINE) {
x = startValue.mX + t * (endValue.mX - startValue.mX);
y = startValue.mY + t * (endValue.mY - startValue.mY);
} else {
x = endValue.mX;
y = endValue.mY;
}
return new PathPoint(PathPoint.MOVE,x,y);
}
}
- 使用
mPath = new CustomPath.Builder()
.moveTo(0, 0)
.setDuration(1000)
.cubicTo(-200, 200, -400, 200, -600, 50)
.build();
/* mPath.moveTo(0, 0);
mPath.cubicTo(-200, 200, -400, 200, -600, 50);
mPath.lineTo(-900,200);
mPath.lineTo(0,0);
mPath.setDuration(1000);*/
mPath.startAnimation(v);
mPath.addBeizeAnimationEnd(new CustomPath.BeizeAnimationEnd() {
@Override
public void animationEnd(Animator animation) {
mLlTitle.setVisibility(View.INVISIBLE);
mFab.setVisibility(View.INVISIBLE);
mLinearLayout.setVisibility(View.VISIBLE);
mToolBar.setBackgroundColor(getResources().getColor(R.color.brand_accent));
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
findViewById(R.id.iv_prev).setAlpha((Float) animation.getAnimatedValue());
findViewById(R.id.iv_pause).setAlpha((Float) animation.getAnimatedValue());
findViewById(R.id.iv_next).setAlpha((Float) animation.getAnimatedValue());
}
});
valueAnimator.start();
}
});
总结:代码其实很简单,主要是公式的套入和在ObjectAnimator的使用情况下需要对源码有一点了解
网友评论