自定义 Bezier 动画和抖动动画的实现

Android · zasdsd · 于 发布 · 最后由 harkben回复 · 514 次阅读
96

之前看到很多贝塞尔的动画效果,都很漂亮,之前有需要用到类似的效果,就先写了下来。

在百度搜索了下, 公式是这样子的:

二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:

我也就照着公式 ,来一个简单的代码:

package com.mj.animapp.anim;

import android.annotation.SuppressLint;

import android.graphics.PointF;

import com.nineoldandroids.animation.TypeEvaluator;

@SuppressLint("NewApi")

public class BezierEvaluatorBear implements TypeEvaluator<PointF> {

/**
* 二次方贝塞尔曲线 B(t)=(1-t)^2*P0+2*t*(1-t)*P1+t^2*P2,t∈[0,1] P0,是我们的起点, P2是终点,
* P1是途径的点 而t则是我们的一个因子,取值范围是0-1
*/

private PointF pointF1;// 中间的点

public BezierEvaluatorBear(PointF pointF1) {

this.pointF1 = pointF1;

}

/**
* 开始和结束的点,这个公式是固定
*/

@Override

public PointF evaluate(float fraction, PointF pointF0, PointF pointF2) {

PointF pointF = new PointF();

pointF.x = (float) ((pointF0.x * (Math.pow((1 - fraction), 2))) + 2

* pointF1.x * fraction * (1 - fraction) + pointF2.x

* Math.pow(fraction, 2));

pointF.y = (float) ((pointF0.y * (Math.pow((1 - fraction), 2))) + 2

* pointF1.y * fraction * (1 - fraction) + pointF2.y

* Math.pow(fraction, 2));

return pointF;

}

}

公式是实现了 , 但是怎么实现整个动画的过程呢?

也是同样的先上代码:

@OnClick(R.id.llLeftRate)

public void llLeftRateOnlick(View view) {

int[] starRect = new int[2];

ivBean.getLocationOnScreen(starRect);

int[] endRect = new int[2];

rlZhangBean.getLocationOnScreen(endRect);

int starx = starRect[0];

int stary = starRect[1] - statusBarHeight;

int endx = 0;

int endy = 0;

for (int i = 0; i < ANMIBEANCOUNT; i++) {

endx = endRect[0]

+ (int) (Math.random() * (rlZhangBean.getWidth() + 1));

endy = (endRect[1] - statusBarHeight)

+ (int) (Math.random() * (rlZhangBean.getHeight() + 1));

mAnmiView.addBezierView(new PointF(starx, stary),

new PointF(endx - 50, endy + 100), new PointF(endx,

endy));

}

ObjectAnimator objAnim = rotationAnim(llLeftRate, 1f);

objAnim.setStartDelay(1000);

objAnim.start();

}

在这个点击事件中我们可以看出,要执行整个动画我们需要 开始的位置 p0, 中间幅度的位置p1, 结束的位置p2。

怎么生成很多个小豆子呢, 就是使用自定义Layout , addview后,执行自定义的动画。看一下源码大家就会明白很多了。
[java] view plain copy
public void addBezierView(PointF pointStart, PointF pointMid, PointF pointEnd) {

this.pointStart = pointStart;

this.pointMid = pointMid;

this.pointEnd = pointEnd;

this.pointMid.set(pointMid.x + mWidth / 2, pointMid.y - mHeight);

this.pointEnd.set(pointEnd.x - mWidth / 2, pointEnd.y - mHeight);

ImageView view = new ImageView(getContext());

int nextInt = mRandom.nextInt(loves.length - 1);

view.setImageDrawable(loves[nextInt]);

view.setLayoutParams(mParams);

addView(view);

ViewCompat.setX(view, pointStart.x);

ViewCompat.setY(view, pointStart.y);

AnimatorSet matorSet = getAnimatorSet(view);

// 设置插补器.

matorSet.setInterpolator(new AccelerateDecelerateInterpolator());

matorSet.start();

}

顺便说下,怎么实现不同的位置显示不同的效果呢?

// 给动画添加一个动画的进度监听;在动画执行的过程中动态的改变view的位置;

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

PointF pointF = (PointF) animation.getAnimatedValue();

ViewCompat.setX(view, pointF.x);

ViewCompat.setY(view, pointF.y);

if (animation.getAnimatedFraction() <= 0.6f) {

ViewCompat.setScaleX(view,

0.6f + animation.getAnimatedFraction());

ViewCompat.setScaleY(view,

0.6f + animation.getAnimatedFraction());

} else {

ViewCompat.setScaleX(view,

1.2f - (animation.getAnimatedFraction() - 0.6f));

ViewCompat.setScaleY(view,

1.2f - (animation.getAnimatedFraction() - 0.6f));

}

// 设置view的透明度,达到动画执行过程view逐渐透明效果;

}

});

这个地方使用了放大缩小,来尝试实现有点3d效果的抛物线。

最后说明下,最后面的抖动效果我使用了nineoldandroid 来实现抖动的效果

public ObjectAnimator rotationAnim(View view, float shakeFactor) {

PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofKeyframe(

"scaleX",

Keyframe.ofFloat(0f, 1f),

Keyframe.ofFloat(.1f, .9f),

Keyframe.ofFloat(.2f, .9f),

Keyframe.ofFloat(.3f, 1.0f),// 1.1f

Keyframe.ofFloat(.4f, 1.0f), Keyframe.ofFloat(.5f, 1.0f),

Keyframe.ofFloat(.6f, 1.0f), Keyframe.ofFloat(.7f, 1.0f),

Keyframe.ofFloat(.8f, 1.0f), Keyframe.ofFloat(.9f, 1.0f),

Keyframe.ofFloat(1f, 1f));

PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofKeyframe(

"scaleY", Keyframe.ofFloat(0f, 1f), Keyframe.ofFloat(.1f, .9f),

Keyframe.ofFloat(.2f, .9f), Keyframe.ofFloat(.3f, 1.0f),

Keyframe.ofFloat(.4f, 1.0f), Keyframe.ofFloat(.5f, 1.0f),

Keyframe.ofFloat(.6f, 1.0f), Keyframe.ofFloat(.7f, 1.0f),

Keyframe.ofFloat(.8f, 1.0f), Keyframe.ofFloat(.9f, 1.0f),

Keyframe.ofFloat(1f, 1f));

PropertyValuesHolder pvhRotate = PropertyValuesHolder.ofKeyframe(

"rotation", Keyframe.ofFloat(0f, 0f),

Keyframe.ofFloat(.1f, -3f * shakeFactor),

Keyframe.ofFloat(.2f, -3f * shakeFactor),

Keyframe.ofFloat(.3f, 3f * shakeFactor),

Keyframe.ofFloat(.4f, -3f * shakeFactor),

Keyframe.ofFloat(.5f, 3f * shakeFactor),

Keyframe.ofFloat(.6f, -3f * shakeFactor),

Keyframe.ofFloat(.7f, 3f * shakeFactor),

Keyframe.ofFloat(.8f, -3f * shakeFactor),

Keyframe.ofFloat(.9f, 3f * shakeFactor),

Keyframe.ofFloat(1f, 0));

return ObjectAnimator.ofPropertyValuesHolder(view, pvhScaleX,

pvhScaleY, pvhRotate).setDuration(1000);

}

这个项目目前已经我已经放在github 上 ,欢迎大家star

https://github.com/zasdsd/BezierAmin

共收到 4 条回复
96
xupeng · #1 ·

兔子

96
xupeng · #2 ·

看见了

30
d_clock · #3 ·

文章排版好差,而且gif演示图都木有。

96
harkben · #4 ·

割一刀



  /**  不重排,要给差评咯  **/
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册