-
贝塞尔曲线
编辑
线性公式
二次方公式
三次方公式
一般参数公式
公式说明
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;
- }
- }