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

别的先不说了,先上效果:



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

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

二次方公式

二次方贝兹曲线的路径由给定点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后,执行自定义的动画。看一下源码大家就会明白很多了。
   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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
贝塞尔曲线可以用于创建平滑的动画效果。以下是一个简单的C++实现bezier动画的示例代码: ```c++ #include <iostream> #include <cmath> #include <vector> using namespace std; // 二维向量 struct Vector2D { float x; float y; }; // 计算组合数 int Combination(int n, int k) { int result = 1; for (int i = 1; i <= k; ++i) { result *= (n - i + 1); result /= i; } return result; } // 计算Bezier曲线上的点 Vector2D BezierCurve(vector<Vector2D>& control_points, float t) { Vector2D result = { 0, 0 }; int n = control_points.size() - 1; for (int i = 0; i <= n; ++i) { float factor = Combination(n, i) * pow(t, i) * pow(1 - t, n - i); result.x += control_points[i].x * factor; result.y += control_points[i].y * factor; } return result; } int main() { // 控制点 vector<Vector2D> control_points = { { 100, 100 }, { 200, 50 }, { 300, 200 }, { 400, 150 } }; // 计算Bezier曲线上的点并输出 for (float t = 0; t <= 1; t += 0.1f) { Vector2D point = BezierCurve(control_points, t); cout << "(" << point.x << ", " << point.y << ")" << endl; } return 0; } ``` 在这个示例中,我们定义了一个二维向量结构体`Vector2D`,用于表示控制点和Bezier曲线上的点。然后定义了`Combination`函数,用于计算组合数。最重要的是`BezierCurve`函数,它接受一个控制点向量和一个参数`t`,并返回Bezier曲线上的点。 我们在`main`函数中定义了四个控制点,并调用`BezierCurve`函数来计算Bezier曲线上的点。在这个例子中,我们使用了一个简单的循环,从0到1递增t,每0.1个单位调用一次`BezierCurve`函数,并输出结果。 这只是一个简单的示例,你可以根据自己的需要更改控制点和步长,以创建平滑的动画效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值