天天看點

自定義Bezier動畫和抖動動畫的實作别的先不說了,先上效果:

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

自定義Bezier動畫和抖動動畫的實作别的先不說了,先上效果:

之前看到很多貝塞爾的動畫效果,都很漂亮,之前有需要用到類似的效果,就先寫了下來。

在百度搜尋了下, 公式是這樣子的:

二次方公式

二次方貝茲曲線的路徑由給定點P0、P1、P2的函數B(t)追蹤:

自定義Bezier動畫和抖動動畫的實作别的先不說了,先上效果:

我也就照着公式 ,來一個簡單的代碼:

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