别的先不说了,先上效果:
之前看到很多贝塞尔的动画效果,都很漂亮,之前有需要用到类似的效果,就先写了下来。
在百度搜索了下, 公式是这样子的:
二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
![](https://i-blog.csdnimg.cn/blog_migrate/ad84e92b84a4867eb5b1a43914bae0ee.png)
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后,执行自定义的动画。看一下源码大家就会明白很多了。
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