Android貝塞爾曲線的簡單應用之——實現仿美團點擊商品掉落購物車效果,附demo和工具類


上一篇:Android貝塞爾曲線的簡單應用之——實現自定義圓形控件內水波紋自動上升效果Demo

效果:

在這裏插入圖片描述

佈局這裏很簡單,一個RecyclerView和一個ImageView,這裏稍微注意下,ConstraintLayout等下我們要用到,所以這裏加了id。

在這裏插入圖片描述

然後是在activity中設置recyclerview的adapter添加一些商品數據,在item的點擊監聽中調用封裝好的工具類:BezierShopCarModule,傳入指定參數,這樣就可以實現商品掉落到購物車的效果了,是不是很easy?哈哈,下面來介紹下封裝的類 BezierShopCarModule
/*設置監聽*/
    private void setListener() {
        callBack = new CallBack() {
            @Override
            public void itemOnClickListener(View view,int position) {
                Log.i(TAG,"點擊了第"+position+"個item");
                //實現貝塞爾曲線效果
                module = new BezierShopCarModule(clMain,view,ivShopCar);
                module.bezierCurveAnimation(MainActivity.this,800,R.mipmap.commodity_phone,view.getWidth(),view.getHeight());
            }
        };
    }

BezierShopCarModule 主要用到的方法就兩個而已,構造方法如下,這裏就要用到開頭說的constraintlayout,傳參的時候加上這個即可。
	private ViewGroup layout;//佈局文件,有標題欄的情況下,需獲取內容佈局的起始點座標,後面的控件座標減去該座標才能得到準確座標值,所以有無標題欄都減去這個值,避免出錯
    private View startView;//起始點控件
    private View endView;//結束點控件

    /**
     * 構造方法
     * @param layout       佈局文件,即xml文件的根佈局layout,用於確定子view的相對位置
     * @param startView    曲線開始的控件
     * @param endView      曲線結束的控件(一般是”購物車“)
     */
    public BezierShopCarModule (ViewGroup layout, View startView, View endView){
        this.layout = layout;
        this.startView = startView;
        this.endView = endView;
    }
然後是實現動畫效果的方法,下面有註釋:
/**
     * 開啓貝塞爾曲線動畫效果
     * @param context           傳入的view所在的activity的上下文變量
     * @param animationTime     動畫執行時間
     * @param imageViewResource 圖片資源
     * @param imageWidth         圖片控件寬度
     * @param imageHeight        圖片控件高度
     * @return                  執行結束,返回true
     */
    public boolean bezierCurveAnimation(Context context,int animationTime,int imageViewResource,int imageWidth,int imageHeight){
        //貝塞爾曲線,起始點
        int[] startPoint = new int[2];
        //貝塞爾曲線,結束點
        int[] endPoint = new int[2];
        //內容佈局起始點,有標題欄的情況下,需獲取內容佈局的起始點座標,後面的控件座標減去該座標才能得到準確座標值,爲確保準確,有無標題欄都減去該座標
        int[] constraintLayoutPoint = new int[2];
        //獲取座標點
        layout.getLocationInWindow(constraintLayoutPoint);
        startView.getLocationInWindow(startPoint);
        endView.getLocationInWindow(endPoint);
        //賦值貝塞爾曲線用到的點
        PointF startF = new PointF();   //起始點
        PointF endF = new PointF();     //結束點
        PointF controllF = new PointF();//控制點

        startF.x = startPoint[0];
        startF.y = startPoint[1] - constraintLayoutPoint[1];//確定起始點Y座標
        endF.x = endPoint[0]+(endView.getWidth()-imageWidth)/2;//使掉落的“商品”砸在“購物車”中間
        endF.y = endPoint[1] - constraintLayoutPoint[1];
        controllF.x = endF.x;
        controllF.y = startF.y;

        //創建控件
        final ImageView imageView = new ImageView(context);
        layout.addView(imageView);
        imageView.setImageResource(imageViewResource);//傳入的圖片資源
        imageView.getLayoutParams().width = imageWidth;//設置大小
        imageView.getLayoutParams().height = imageHeight;
        imageView.setVisibility(View.VISIBLE);
        imageView.setX(startF.x);
        imageView.setY(startF.y);

        //插值器
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new BezierTypeEvaluator(controllF),startF,endF);
        //過程監聽
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //獲取曲線座標
                PointF pointF = (PointF) valueAnimator.getAnimatedValue();
                //設置圖片座標
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
            }
        });
        //動畫完成監聽
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                //移除控件
                layout.removeView(imageView);
            }
        });

        //購物車動畫
        //屬性動畫,縮放
        ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(endView,"scaleX",0.8f,1.0f);
        ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(endView,"scaleY",0.8f,1.0f);
        //加速掉落
        objectAnimatorX.setInterpolator(new AccelerateInterpolator());
        objectAnimatorY.setInterpolator(new AccelerateInterpolator());
        //設置動畫播放順序
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(objectAnimatorX).with(objectAnimatorY).after(valueAnimator);
        //設置動畫時長,啓動
        animatorSet.setDuration(animationTime);
        animatorSet.start();
        return true;
    }
最後還有一個自定義的插值器,這是實現貝塞爾曲線的關鍵:
/**
     * Created by Given on 2019/2/22 0022.
     * 自定義插值器,用於實現貝塞爾曲線效果
     */
    public class BezierTypeEvaluator implements TypeEvaluator<PointF> {
        private PointF controllPoint;

        public BezierTypeEvaluator(PointF controllPoint){
            this.controllPoint = controllPoint;
        }

        @Override
        public PointF evaluate(float v, PointF startValue, PointF endValue) {

            PointF pointCur = new PointF();

            //基於二階貝塞爾曲線公式,計算出曲線座標點
            pointCur.x = (1-v)*(1-v)*startValue.x + 2*v*(1-v)*controllPoint.x + v*v*endValue.x;
            pointCur.y = (1-v)*(1-v)*startValue.y + 2*v*(1-v)*controllPoint.y + v*v*endValue.y;

            return pointCur;
        }
    }
以上就是這個封裝的工具類裏面用到的內容,用起來也很簡單,方便以後移植到其它項目中。

Demo下載:https://download.csdn.net/download/qq_37717853/10970623

項目參考博客:https://www.cnblogs.com/wjtaigwh/p/6689684.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章