
-
贝塞尔曲线
编辑
线性公式

二次方公式

三次方公式

一般参数公式

公式说明
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
mFactor其实一直都是1,因为配置文件并没有提供设置其它值的入口,默认会是1。mDoubleFactor是2,由此可见,这个方法其实就 是个x^2的曲线。当input=0.3时,返回值=0.09,假如这个动画的总时长是1秒,也就是说,在0.3秒的时候只是执行0.09秒时候的效果。 这样说可能还有点难理解。
其实这个速度和x^2这条抛物线的斜率的变化是有关的,和斜率的变化率是正比关系。比如,上面这个加速插补器的曲线就如下图:
另附系统提供的其它几个插补器的曲线图:
1.AccelerateDecelerateInterpolator 加速减速插补器
取值是[0,1],可见,从原点开始,斜率是0,先圆滑地慢慢增大,再慢慢减小,最后返回值还是1。这就是一个先加速再减速的效果。而且整个过程是平滑变化的。这也是数学的奥妙啊。
2.DecelerateInterpolator 减速插补器
明显,虽然斜率一直是大过正常值(因为开始时执行较快,后来才慢慢回归正常时间,但直到最后一刻才回到),但斜率一直在减小,是一个减速的过程。
3.AnticipateInterpolator 向前插补器
这是一条符合g(x)=3x^3-2x^2的曲线。前面2/3秒之前(假设整个过程是1秒),返回值是负数。如果这是一个直线运动的动画,这段时间会向设 定的相反的方向运动一点,而且速度显得稍缓(反方向先加速再减速)。这之后以一个较快速度跑到终点(大概0.7秒时会回到原点)。
4.AnticipateOvershootInterpolator 向前向后插补器
这是3条曲线合并起来的图,我们只需要较深色的那条x轴上[0,0.5)和稍浅那条[0.5,1]这两段就可以。可以看到,前面一点时间有一段负数的返回值,而后面有一段大于1的返回值,这就有了向前向后的效果。
5.OvershootInterpolator 超出插补器
/**
* 添加一个View.
*/
@SuppressLint("NewApi")
public void addBezierView() {
ImageView view = new ImageView(getContext());
int nextInt = mRandom.nextInt(loves.length - 1);
view.setImageDrawable(loves[nextInt]);
mParams.addRule(CENTER_IN_PARENT);
mParams.addRule(ALIGN_PARENT_BOTTOM);
view.setLayoutParams(mParams);
addView(view);
AnimatorSet matorSet = getAnimatorSet(view);
matorSet.setInterpolator(interpolators[mRandom.nextInt(interpolators.length-1)]);
matorSet.start();
}
/**
* 获取一个贝塞尔+平移等动画效果的AnimatorSet;
*
* @param view
* @return
*/
@SuppressLint("NewApi")
private AnimatorSet getAnimatorSet(final ImageView view) {
// 创建动画
AnimatorSet set = new AnimatorSet();
ObjectAnimator trax = ObjectAnimator.ofFloat(view, "scaleX", 0.4f, 1f);
ObjectAnimator tray = ObjectAnimator.ofFloat(view, "scaleY", 0.4f, 1f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 0.4f, 1f);
// 三个动画一起执行
AnimatorSet enterSet = new AnimatorSet();
enterSet.setDuration(mPDuration);
enterSet.playTogether(trax, tray, alpha);
// 创建贝塞尔动画
ValueAnimator bezierAnimator = getBezierAnimator(view);
// 所有动画一起执行
set.playSequentially(enterSet, bezierAnimator);
set.setTarget(view);
// 给动画添加一个执行的状态监听,当动画执行结束的时候把view释放掉.
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
removeView(view);
super.onAnimationEnd(animation);
}
});
return set;
}
/**
* 获取贝塞尔动画
*
* @param view
* @return
*/
@SuppressLint("NewApi")
private ValueAnimator getBezierAnimator(final ImageView view) {
// 初始化贝塞尔动画的几个点
PointF pointF0 = new PointF((cWidth - mWidth) / 2, cHeight - mHeight);
PointF pointF1 = getTogglePointF(1);
PointF pointF2 = getTogglePointF(2);
PointF pointF3 = new PointF(mRandom.nextInt(cWidth), 0);
// 贝塞尔动画的路径由 一个估值器来表示.
// 获取一个估值器,估值器的点集为pointF1,pointF2;
BezierEvaluator bezierEvaluator = new BezierEvaluator(pointF1, pointF2);
ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierEvaluator,
pointF0, pointF3);
valueAnimator.setDuration(mBDuration);
// 给动画添加一个动画的进度监听;在动画执行的过程中动态的改变view的位置;
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
view.setX(pointF.x);
view.setY(pointF.y);
// 设置view的透明度,达到动画执行过程view逐渐透明效果;
view.setAlpha(1 - animation.getAnimatedFraction());
}
});
return valueAnimator;
}
/**
* 生成不同的PointF;
*
* @param i
* 从上到下标记依次为1-....
* @return
*/
private PointF getTogglePointF(int i) {
PointF pointF = new PointF();
pointF.x = mRandom.nextInt(cWidth);
float nextFloat = mRandom.nextFloat();
float nextFloat2 = mRandom.nextFloat();
if (nextFloat > 0.5)
nextFloat /= 2;
if (nextFloat2 < 0.5)
nextFloat2 /= 0.5;
if (i == 1) {
pointF.y = (float) (cHeight * nextFloat);
} else if (i == 2) {
pointF.y = (float) ((cHeight - mHeight )* nextFloat2);
}
return pointF;
}
public class BezierEvaluator implements TypeEvaluator<PointF> {
private PointF pointF1;
private PointF pointF2;
public BezierEvaluator(PointF pointF1, PointF pointF2) {
this.pointF1 = pointF1;
this.pointF2 = pointF2;
}
@Override
public PointF evaluate(float fraction, PointF pointF0, PointF pointF3) {
// TODO Auto-generated method stub
PointF pointF = new PointF();
//贝塞尔曲线的实现.根据贝塞尔曲线的公式得到x.y的值
pointF.x = (float) ((pointF0.x * (Math.pow((1 - fraction), 3))) + 3
* pointF1.x * fraction * (Math.pow((1 - fraction), 2)) + 3
* pointF2.x * (Math.pow(fraction, 2) * (1 - fraction)) + pointF3.x
* (Math.pow(fraction, 3)));
pointF.y = (float) ((pointF0.y * (Math.pow((1 - fraction), 3))) + 3
* pointF1.y * fraction * (Math.pow((1 - fraction), 2)) + 3
* pointF2.y * (Math.pow(fraction, 2) * (1 - fraction)) + pointF3.y
* (Math.pow(fraction, 3)));
return pointF;
}
}