1. 程式人生 > >仿某直播平臺的點贊效果

仿某直播平臺的點贊效果

現在的直播平臺已經是多的不得了了,而給主播點讚的效果,也是各不相同,今天,我們來自定義一個點讚的效果!
先上效果:

這裡寫圖片描述

當點選點贊按鈕的時候,就會有不同顏色的心型從底部冒出,並按照不規則的路線運動,在運動過程中,伴隨著各種動畫!

好了,話不多說,直接上程式碼:

/**
 * Created by DELL on 2017/9/16.
 * Description : 花束點贊效果
 */

public class PraiseView extends RelativeLayout {

    private int[] drawables;
    private Context mContext;
    //圖片的寬高
private int mDrawableHeight; private int mDrawableWidth; //隨機數 private Random mRandom; public PraiseView(Context context) { this(context,null); } public PraiseView(Context context, AttributeSet attrs) { this(context, attrs,0); } public PraiseView
(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; //建立隨機數 在後面的貝塞爾取點鐘會用到 mRandom = new Random(); //初始化心形圖片 drawables = new int[]{R.drawable.pl_blue,R.drawable.pl_red,R.drawable.pl_yellow}; //獲取心形圖片的寬高
Drawable drawable = ContextCompat.getDrawable(context,drawables[0]); mDrawableHeight = drawable.getIntrinsicHeight(); mDrawableWidth = drawable.getIntrinsicWidth(); } //在螢幕底部新增心形圖片 public void addDrawables(){ final ImageView imageView = new ImageView(mContext); imageView.setImageResource(drawables[mRandom.nextInt(drawables.length-1)]); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); params.addRule(ALIGN_PARENT_BOTTOM); params.addRule(CENTER_HORIZONTAL); imageView.setLayoutParams(params); addView(imageView); //建立並開啟動畫效果 AnimatorSet animatorSet = getAnimator(imageView); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); //在動畫執行結束之後,移除該view removeView(imageView); } }); animatorSet.start(); } //建立動畫 /** * 剛開始做縮放和漸變動畫 結束後開始做移動動畫 * @param imageView * @return */ private AnimatorSet getAnimator(ImageView imageView){ //縮放動畫 ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(imageView,"scaleX",0.3f,1f); ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(imageView,"scaleY",0.3f,1f); //漸變動畫 ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(imageView,"alpha",0.3f,1f); AnimatorSet set = new AnimatorSet(); set.playTogether(scaleXAnimator,scaleYAnimator,alphaAnimator); set.setDuration(300); //建立平移動畫並新增到set執行完成之後執行 AnimatorSet wholeAnimator = new AnimatorSet(); //按照順序執行 wholeAnimator.playSequentially(set,getBeizerAnimator(imageView)); return wholeAnimator; } private ValueAnimator getBeizerAnimator(final ImageView imageView){ //首先先確定需要用到的四個點 //點0是在圖片開始的中心點 final PointF point0 = new PointF(getWidth()/2 - mDrawableWidth/2,getHeight() - mDrawableHeight); //點1 點2是貝塞爾曲線的控制點 需要控制的是,點2的高度要大於點1的高度 PointF point1 = getPoint(1); PointF point2 = getPoint(2); PointF point3 = new PointF(mRandom.nextInt(getWidth()/2) - mDrawableWidth/2,0); BeizerEvalator beizerEvalator = new BeizerEvalator(point1,point2); ValueAnimator beizerAnimator = ObjectAnimator.ofObject(beizerEvalator,point0,point3); beizerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); beizerAnimator.setDuration(4000); beizerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //在執行過程中會呼叫該方法 PointF pointF = (PointF) animation.getAnimatedValue(); imageView.setX(pointF.x); imageView.setY(pointF.y); //設定移動過程中的漸變 //首先獲取當前的fraction float fraction = animation.getAnimatedFraction(); imageView.setAlpha(1-fraction); } }); return beizerAnimator; } private PointF getPoint(int i){ return new PointF(mRandom.nextInt(getWidth())- mDrawableWidth,mRandom.nextInt(getHeight()/2) + (i-1)*getHeight()/2); } }

然後,我們需要一個估值器,來確定在某一時刻,沿著貝塞爾曲線的路徑的點(這邊,其實只要套公式就可以了)

/**
 * Created by DELL on 2017/9/16.
 * Description : 貝塞爾運動軌跡估值器
 */

public class BeizerEvalator implements TypeEvaluator<PointF> {

    private PointF point1,point2;

    public BeizerEvalator(PointF point1,PointF point2){
        this.point1 = point1;
        this.point2 = point2;
    }

    //直接套用貝塞爾三階公式
    @Override
    public PointF evaluate(float fraction, PointF point0, PointF point3) {

        PointF pointF = new PointF();

        pointF.x = point0.x*(1-fraction)*(1-fraction)*(1-fraction)
                + 3*point1.x*fraction*(1-fraction)*(1-fraction)
                + 3*point2.x*fraction*fraction*(1-fraction)
                + point3.x*fraction*fraction*fraction;

        pointF.y = point0.y*(1-fraction)*(1-fraction)*(1-fraction)
                + 3*point1.y*fraction*(1-fraction)*(1-fraction)
                + 3*point2.y*fraction*fraction*(1-fraction)
                + point3.y*fraction*fraction*fraction;

        return pointF;
    }
}

按照以往的風格,註釋都加在程式碼中了,如果大家還發現了什麼問題,請回復我,大家一起討論下!

最後,再來看一次效果:
這裡寫圖片描述