Android -- 貝塞爾二階實現餓了么加入購物車效果


1,上周我們實現了簡單的三階貝塞爾曲線效果實例,今天是使用二階貝塞爾曲線加動畫實現的加入購物車效果,在碼代碼過程中出現了些問題,過一下和大家來探討探討,先看一下效果圖

  

2,從上面的效果來看我們基本上可以把功能拆分為兩個動畫效果:+號圖片按照曲線掉下(曲線的軌跡就是一個簡單的貝塞爾曲線)、購物車圖標從縮小到放大。知道了實現的原理我們開始我們功能的實現

  • 實現基本基本布局、RecyclerView展示數據

  從上面的效果我們可以得到,我們的布局是一個簡單的RecyclerView和下面的RelativeLayout,布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_layout"
    tools:context="com.qianmo.beziershopcart.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>


    <LinearLayout
        android:id="@+id/shopping_cart_bottom"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:background="#fd383838"
        android:orientation="horizontal">

    </LinearLayout>

    <FrameLayout
        android:id="@+id/shopping_cart_layout"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="35dp"
        android:background="@drawable/circle"
        android:clickable="true">

        <ImageView
            android:id="@+id/shopping_cart"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_gravity="center"
            android:src="@mipmap/ic_shopping_cart_white_24dp"/>
    </FrameLayout>
</RelativeLayout>

  添加Shop實體類、添加RecyclerView的Adapter

package com.qianmo.beziershopcart;

/**
 * Created by wangjitao on 2017/4/10 0010.
 * E-Mail:543441727@qq.com
 */

public class ShopBean {

    private String title;
    private String price;
    private int count;

    public ShopBean(String title, String price, int count) {
        this.title = title;
        this.price = price;
        this.count = count;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

  適配器

package com.qianmo.beziershopcart;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

/**
 * Created by Administrator on 2017/4/10 0010.
 * E-Mail:543441727@qq.com
 */

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<ShopBean> datas;
    private Context mContext;
    private ShopOnClickListtener mShopOnClickListtener;

    public MyAdapter(List<ShopBean> datas, Context mContext) {
        this.datas = datas;
        this.mContext = mContext;
    }

    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_shop_menu, parent, false));
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder holder, final int position) {
        holder.shop_name.setText(datas.get(position).getTitle());
        holder.shop_price.setText(datas.get(position).getPrice());
        holder.count.setText(datas.get(position).getCount() + "");

        holder.ic_add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mShopOnClickListtener != null) {
                    mShopOnClickListtener.add(v, position);
                }
            }
        });
        holder.ic_reduce.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mShopOnClickListtener != null) {
                    mShopOnClickListtener.remove(v, position);
                }

            }
        });
    }

    @Override
    public int getItemCount() {
        return datas == null ? 0 : datas.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView shop_name;
        TextView shop_price;
        TextView count;
        ImageView ic_add;
        ImageView ic_reduce;

        public ViewHolder(View itemView) {
            super(itemView);
            shop_name = (TextView) itemView.findViewById(R.id.tv_title);
            shop_price = (TextView) itemView.findViewById(R.id.tv_price);
            count = (TextView) itemView.findViewById(R.id.tv_count);
            ic_add = (ImageView) itemView.findViewById(R.id.iv_add);
            ic_reduce = (ImageView) itemView.findViewById(R.id.iv_remove);
        }
    }

    public ShopOnClickListtener getShopOnClickListtener() {
        return mShopOnClickListtener;
    }

    public void setShopOnClickListtener(ShopOnClickListtener mShopOnClickListtener) {
        this.mShopOnClickListtener = mShopOnClickListtener;
    }


    public interface ShopOnClickListtener {

        void add(View view, int position);

        void remove(View view, int position);
    }
}

  在Activity中簡單的添加數據

package com.qianmo.beziershopcart;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.graphics.PointF;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements MyAdapter.ShopOnClickListtener {
    private Context mContext = MainActivity.this;

    private RelativeLayout main_layout;
    private RecyclerView mRecyclerView;
    private ImageView mImageViewShopCat;
    private List<ShopBean> datas;
    private MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();


    }

    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
        mImageViewShopCat = (ImageView) findViewById(R.id.shopping_cart);
        main_layout = (RelativeLayout) findViewById(R.id.main_layout);
        initData();
    }

    private void initData() {
        datas = new ArrayList<>();
        datas.add(new ShopBean("面包", "1.00", 10));
        datas.add(new ShopBean("蛋撻", "1.00", 10));
        datas.add(new ShopBean("牛奶", "1.00", 10));
        datas.add(new ShopBean("腸粉", "1.00", 10));
        datas.add(new ShopBean("綠茶餅", "1.00", 10));
        datas.add(new ShopBean("花卷", "1.00", 10));
        datas.add(new ShopBean("包子", "1.00", 10));

        datas.add(new ShopBean("粥", "1.00", 10));
        datas.add(new ShopBean("炒飯", "1.00", 10));
        datas.add(new ShopBean("炒米粉", "1.00", 10));
        datas.add(new ShopBean("炒粿條", "1.00", 10));
        datas.add(new ShopBean("炒牛河", "1.00", 10));
        datas.add(new ShopBean("炒菜", "1.00", 10));

        datas.add(new ShopBean("淋菜", "1.00", 10));
        datas.add(new ShopBean("川菜", "1.00", 10));
        datas.add(new ShopBean("湘菜", "1.00", 10));
        datas.add(new ShopBean("粵菜", "1.00", 10));
        datas.add(new ShopBean("贛菜", "1.00", 10));
        datas.add(new ShopBean("東北菜", "1.00", 10));

        datas.add(new ShopBean("淋菜", "1.00", 10));
        datas.add(new ShopBean("川菜", "1.00", 10));
        datas.add(new ShopBean("湘菜", "1.00", 10));
        datas.add(new ShopBean("粵菜", "1.00", 10));
        datas.add(new ShopBean("贛菜", "1.00", 10));
        datas.add(new ShopBean("東北菜", "1.00", 10));

        mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
        mRecyclerView.addItemDecoration(new RecyclerViewDivider(mContext, LinearLayoutManager.VERTICAL, 50, ContextCompat.getColor(mContext, R.color.colorAccent)));
        myAdapter = new MyAdapter(datas, mContext);
        mRecyclerView.setAdapter(myAdapter);
        myAdapter.setShopOnClickListtener(this);
    }


    @Override
    public void add(final View view, int position) {
       Toast.makeText(mContext, "加", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void remove(View view, int position) {
     Toast.makeText(mContext, "減", Toast.LENGTH_SHORT).show();
    }
}

  看一下我們的效果:

  

  OK,大致的展示效果基本上是實現了

  • 使用加入購物車效果

  下面我們來實現貝塞爾曲線效果,首先獲取兩個數據點:一個是每次點擊“+”號的坐標位置、一個是下面紅色的購物車圖標。控制點我打算取開始點的Y坐標和結束點的X坐標,那么怎么獲取當前控件相對於整個屏幕的坐標呢,這里View里面有一個getLocationInWindow()方法(這里要留心一下這個方法),然后不了解的同學可以搜索一下view.getLocationInWindow(int[] location)和view.getLocationOnScreen(int[] location),方法的區別,這里我從網上偷了了一個圖,如下:

  getLocationInWindow是以B為原點的C的坐標
  getLocationOnScreen以A為原點

  ok,這樣我們看一下我們的貝塞爾三個坐標的初始化

 @Override
    public void add(final View view, int position) {
        //貝塞爾起始數據點
        int[] startPosition = new int[2];
        //貝塞爾結束數據點
        int[] endPosition = new int[2];
        //控制點
        int[] recyclerPosition = new int[2];

        view.getLocationInWindow(startPosition);
        mImageViewShopCat.getLocationInWindow(endPosition);

        PointF startF = new PointF();
        PointF endF = new PointF();
        PointF controllF = new PointF();

       
       startF.x = startPosition[0];
       startF.y = startPosition[1] ;
       endF.x = endPosition[0];
       endF.y = endPosition[1];
       controllF.y = startF.y;
}

  繼續,自定義差值器,我們按照貝塞爾的三階公式來套,上一篇詳細的介紹過了就不在廢話了,這里不懂的話建議你去看一下我的上一篇博客,里面有詳細的介紹

  

package com.qianmo.beziershopcart;

import android.animation.TypeEvaluator;
import android.graphics.PointF;

/**
 * Created by Administrator on 2017/4/10 0010.
 * E-Mail:543441727@qq.com
 */

public class BezierTypeEvaluator implements TypeEvaluator<PointF> {
    private PointF mControllPoint;

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

    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        PointF pointCur = new PointF();
        pointCur.x = (1 - fraction) * (1 - fraction) * startValue.x + 2 * fraction * (1 - fraction) * mControllPoint.x + fraction * fraction * endValue.x;
        pointCur.y = (1 - fraction) * (1 - fraction) * startValue.y + 2 * fraction * (1 - fraction) * mControllPoint.y + fraction * fraction * endValue.y;
        return pointCur;
    }
}

  開啟動畫自動調用

@Override
    public void add(final View view, int position) {
        //貝塞爾起始數據點
        int[] startPosition = new int[2];
        //貝塞爾結束數據點
        int[] endPosition = new int[2];
        
        view.getLocationInWindow(startPosition);
        mImageViewShopCat.getLocationInWindow(endPosition);

        PointF startF = new PointF();
        PointF endF = new PointF();
        PointF controllF = new PointF();

        
        startF.x = startPosition[0];
        startF.y = startPosition[1] ;
        endF.x = endPosition[0];
        endF.y = endPosition[1];
        controllF.x = endF.x;
        controllF.y = startF.y;

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new BezierTypeEvaluator(controllF), startF, endF);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF pointF = (PointF) animation.getAnimatedValue();
                view.setX(pointF.x);
                view.setY(pointF.y);
//                Log.i("wangjtiao", "viewF:" + view.getX() + "," + view.getY());
            }
        });
        valueAnimator .setDuration(800);
        valueAnimator .start();
    }

  按照我們的思路,這個功能基本上是實現了,感覺很簡單,又可以多了些時間去打兩把王者農葯了,看一下我們的效果圖:

  

  呃!!!我的動畫呢??? ,看一下我們打印動畫軌跡的效果

04-10 03:55:37.271 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:899.42816,608.6747
04-10 03:55:37.306 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:841.05066,615.05853
04-10 03:55:37.369 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:700.9506,644.04346
04-10 03:55:37.399 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:626.5742,669.1555
04-10 03:55:37.427 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:552.1316,703.05035
04-10 03:55:37.474 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:477.8907,747.9864
04-10 03:55:37.502 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:410.36102,801.63885
04-10 03:55:37.528 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:348.99896,864.93835
04-10 03:55:37.549 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:320.21585,901.0647
04-10 03:55:37.601 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:247.92773,1019.08307
04-10 03:55:37.629 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:210.69424,1104.1696
04-10 03:55:37.650 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:194.71275,1149.3108
04-10 03:55:37.672 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:180.81482,1194.8556
04-10 03:55:37.716 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:150.94038,1327.2924
04-10 03:55:37.744 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:138.87828,1409.5398
04-10 03:55:37.771 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:134.5641,1449.0864
04-10 03:55:37.799 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:129.06772,1518.4921
04-10 03:55:37.813 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:127.390335,1549.7286
04-10 03:55:37.852 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:125.646034,1600.0463
04-10 03:55:37.873 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:125.263214,1620.108
04-10 03:55:37.902 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:125.0176,1646.6577
04-10 03:55:37.932 29510-29510/com.qianmo.beziershopcart I/wangjtiao: viewF:125.0,1656.0

  view的坐標一直在改變啊!思路上沒什么問題啊,想了好久,會不會是因為這是RecyclerView的item的ImageView,是不是它不能超過它父控件的距離呢?(到最后我也沒搞懂為什么不顯示view,如果知道的同學請告知一下),姑且算是這個問題,那我們就每次都new一個ImageView,添加到主布局中,代碼如下:

@Override
    public void add(final View view, int position) {
        //貝塞爾起始數據點
        int[] startPosition = new int[2];
        //貝塞爾結束數據點
        int[] endPosition = new int[2];
        //控制點
        int[] recyclerPosition = new int[2];

        view.getLocationInWindow(startPosition);
        mImageViewShopCat.getLocationInWindow(endPosition);
        mRecyclerView.getLocationInWindow(recyclerPosition);

        PointF startF = new PointF();
        PointF endF = new PointF();
        PointF controllF = new PointF();


        startF.x = startPosition[0];
        startF.y = startPosition[1];
        endF.x = endPosition[0];
        endF.y = endPosition[1];
        controllF.x = endF.x;
        controllF.y = startF.y;

        Log.i("wangjtiao", "startF:" + startF.x + "," + startF.y);
        Log.i("wangjtiao", "endF:" + endF.x + "," + endF.y);
        Log.i("wangjtiao", "ControllF:" + endF.x + "," + controllF.y);
        Log.i("wangjtiao", "ControllF:" + recyclerPosition[0] + "," + recyclerPosition[1]);

        final ImageView imageView = new ImageView(this);
        main_layout.addView(imageView);
        imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
        imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        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 animation) {
                PointF pointF = (PointF) animation.getAnimatedValue();
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
                Log.i("wangjtiao", "viewF:" + view.getX() + "," + view.getY());
            }
        });


        valueAnimator.setDuration(800);
        valueAnimator.start();
    }

  效果如下:

  

  ??這又是什么鬼,兩個控制點出問題了??既然控制點出問題了我們來看看我們控制點怎么得到的:view.getLocationInWindow(int[] location)和view.getLocationOnScreen(int[] location),,感覺也沒什么問題啊   我們打印一下我們的貝塞爾兩個數據點和一個控制點

04-10 02:45:33.179 32056-32056/com.qianmo.beziershopcart I/wangjtiao: startF:1014.0,242.0
04-10 02:45:33.183 32056-32056/com.qianmo.beziershopcart I/wangjtiao: endF:125.0,1656.0
04-10 02:45:33.183 32056-32056/com.qianmo.beziershopcart I/wangjtiao: ControllF:125.0,242.0

  ok,這里我們看不到我們的效果,我們將view.getLocationInWindow(int[] location)替換成view.getLocationOnScreen(int[] location)

04-10 02:40:44.161 27735-27735/com.qianmo.beziershopcart I/wangjtiao: startF:1014.0,242.0
04-10 02:40:44.161 27735-27735/com.qianmo.beziershopcart I/wangjtiao: endF:125.0,1656.0
04-10 02:45:33.183 32056-32056/com.qianmo.beziershopcart I/wangjtiao: ControllF:125.0,242.0

  ???為什么兩次獲取的坐標都是一樣的,還有我們的上面動畫為什么會偏差這個多,感覺這個高度貌似是我們的狀態欄和標題欄的高度啊  ,為了驗證我們的猜想,我們隱藏掉狀態欄和標題欄試試

1 //獲取當前窗體
2 final Window window = getWindow();
3 //隱藏狀態欄
4  window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
5 //隱藏標題欄
6 requestWindowFeature(Window.FEATURE_NO_TITLE);

  效果如下:

  效果實現了,沒問題,說明真的是這個問題,那view.getLocationInWindow(int[] location)按照別人博客里面說的就是取的相對坐標啊,我們獲取一下我們主界面的mRecyclerView的坐標看看

04-10 02:45:33.183 32056-32056/com.qianmo.beziershopcart I/wangjtiao: ControllF:0,210

  可以看到我們的標題欄+狀態欄高度是210,但是我們起始點的坐標是(1014,242)這個有問題啊,應該是(1014,32)這樣我們的動畫才會在正確的起始位置和結束位置啊。帶着我們的疑問,查了半天資料,終於在一個論壇發現了

因為你的代碼顯示的界面  contentView < window = screen
為什么會相等呢,因為此時的Window就是包含狀態欄+contentView的大小
不是你認為的  contentView = window < screen
除非你的view是從dialog 或者 popupWindow 上顯示,
這時候getLocationInWindow獲得的值就是相對的坐標。

  所以getLocationInWindow方法獲取的是狀態欄+contentView的大小,而不是我們以為的contentView的大小,知道了這里我們基本上就知道怎么解決這個問題了,只需要減去這個高度就可以了,我們可以直接減去mRecyclerView的Y坐標即可,代碼如下:

 @Override
    public void add(final View view, int position) {
        //貝塞爾起始數據點
        int[] startPosition = new int[2];
        //貝塞爾結束數據點
        int[] endPosition = new int[2];
        //控制點
        int[] recyclerPosition = new int[2];

        view.getLocationInWindow(startPosition);
        mImageViewShopCat.getLocationInWindow(endPosition);
        mRecyclerView.getLocationInWindow(recyclerPosition);

        PointF startF = new PointF();
        PointF endF = new PointF();
        PointF controllF = new PointF();

        startF.x = startPosition[0];
        startF.y = startPosition[1] - recyclerPosition[1];
        endF.x = endPosition[0];
        endF.y = endPosition[1] - recyclerPosition[1];
        controllF.x = endF.x;
        controllF.y = startF.y;

        final ImageView imageView = new ImageView(this);
        main_layout.addView(imageView);
        imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
        imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        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 animation) {
                PointF pointF = (PointF) animation.getAnimatedValue();
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
                Log.i("wangjtiao", "viewF:" + view.getX() + "," + view.getY());
            }
        });


        valueAnimator.setDuration(800);
        valueAnimator.start();
    }

  看一下效果:

  

  沒問題了,這里的位置也沒什么問題,再添加動畫完成監聽,移除剛剛new的ImageView

valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                imageView.setVisibility(View.GONE);
                main_layout.removeView(imageView);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
  • 購物車圖標從縮小到放大的實現

  這個就很簡單了,就是一個簡單的屬性動畫,然后將上面這幾個動畫放在集合中,代碼如下:

@Override
    public void add(final View view, int position) {
        //貝塞爾起始數據點
        int[] startPosition = new int[2];
        //貝塞爾結束數據點
        int[] endPosition = new int[2];
        //控制點
        int[] recyclerPosition = new int[2];

        view.getLocationInWindow(startPosition);
        mImageViewShopCat.getLocationInWindow(endPosition);
        mRecyclerView.getLocationInWindow(recyclerPosition);

        PointF startF = new PointF();
        PointF endF = new PointF();
        PointF controllF = new PointF();

        startF.x = startPosition[0];
        startF.y = startPosition[1] - recyclerPosition[1];
        endF.x = endPosition[0];
        endF.y = endPosition[1] - recyclerPosition[1];
        controllF.x = endF.x;
        controllF.y = startF.y;

        final ImageView imageView = new ImageView(this);
        main_layout.addView(imageView);
        imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
        imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
        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 animation) {
                PointF pointF = (PointF) animation.getAnimatedValue();
                imageView.setX(pointF.x);
                imageView.setY(pointF.y);
                Log.i("wangjtiao", "viewF:" + view.getX() + "," + view.getY());
            }
        });


        ObjectAnimator objectAnimatorX = new ObjectAnimator().ofFloat(mImageViewShopCat, "scaleX", 0.6f, 1.0f);
        ObjectAnimator objectAnimatorY = new ObjectAnimator().ofFloat(mImageViewShopCat, "scaleY", 0.6f, 1.0f);
        objectAnimatorX.setInterpolator(new AccelerateInterpolator());
        objectAnimatorY.setInterpolator(new AccelerateInterpolator());
        AnimatorSet set = new AnimatorSet();
        set.play(objectAnimatorX).with(objectAnimatorY).after(valueAnimator);
        set.setDuration(800);
        set.start();
    }

  最后的效果:

  

  ok,這樣就實現了我們的效果了,有沒有很簡單,二階且三個點都是固定的貝塞爾還是很簡單的嘛,github代碼下載

  但是這里還有個遺留的問題還是沒搞懂,為什么RecyclerView的item的ImageView的動畫效果不顯示!!!!知道的同學請留言或者私信一下,感激(抱拳)了各位。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM