溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android怎么實現(xiàn)購物車添加商品動畫

發(fā)布時間:2021-04-17 09:51:48 來源:億速云 閱讀:149 作者:小新 欄目:移動開發(fā)

這篇文章將為大家詳細講解有關Android怎么實現(xiàn)購物車添加商品動畫,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

實現(xiàn)需求:

在商品列表頁面,從列表Item 添加商品的時候,需要一個動畫,仿佛是是往購物車里添加商品。

實現(xiàn)思路:

  1. 獲取起始點與終點的坐標,利用PathMeasure 繪制貝塞爾曲線;

  2. 為點擊的Item 商品View 設置屬性動畫;

  3. 監(jiān)聽屬性動畫的update,改變View 的坐標;

實現(xiàn)效果:

Android怎么實現(xiàn)購物車添加商品動畫

實現(xiàn)中會用到 PathMeasure 類:

我們主要使用它兩個方法:

1、獲取長度:

/** //獲取弧線的總長度(周長)
   * Return the total length of the current contour, or 0 if no path is
   * associated with this measure object.
   */
  public float getLength() {
    return native_getLength(native_instance);//系統(tǒng)調用native 方法;
  }

2、獲取坐標:

/**
   * Pins distance to 0 <= distance <= getLength(), and then computes the
   * corresponding position and tangent. Returns false if there is no path,
   * or a zero-length path was specified, in which case position and tangent
   * are unchanged.
   *
   * @param distance The distance along the current contour to sample
   * @param pos If not null, eturns the sampled position (x==[0], y==[1])
   * @param tan If not null, returns the sampled tangent (x==[0], y==[1])
   * @return false if there was no path associated with this measure object
  */
  public boolean getPosTan(float distance, float pos[], float tan[]) {
    if (pos != null && pos.length < 2 ||
      tan != null && tan.length < 2) {
      throw new ArrayIndexOutOfBoundsException();
    }
    return native_getPosTan(native_instance, distance, pos, tan);
  }

方法 getPosTan(float distance, float pos[],float tan[]) - path 為 null ,返回 false
distance 為一個 0 - getLength() 之間的值,根據(jù)這個值 PathMeasure 會計算出當前點的坐標封裝到 pos 中。上面這句話我們可以這么來理解,不管實際 Path 多么的復雜,PathMeasure 都相當于做了一個事情,就是把 Path “拉直”,然后給了我們一個接口(getLength)告訴我們path的總長度,然后我們想要知道具體某一點的坐標,只需要用相對的distance去取即可,這樣就省去了自己用函數(shù)模擬path,然后計算獲取點坐標的過程。

代碼如下:

public class GoodsListActivity extends AppCompatActivity {

  private RelativeLayout mRootRl;
  private RecyclerView mGoodsRecyclerView;
  private ImageView mCarImageView;
  private TextView mCountTv;

  private List<Bitmap> mBitmapList = new ArrayList<>();
  private PathMeasure mPathMeasure;
  private float[] mCurrentPosition = new float[2];
  private int mCount = 0;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_goods_list);
    initView();
    initData();
    GoodsAdapter goodsAdapter = new GoodsAdapter(mBitmapList);
    mGoodsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mGoodsRecyclerView.setAdapter(goodsAdapter);
  }

  private void initView(){
    mGoodsRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    mCarImageView = (ImageView)findViewById(R.id.imageview_shop_car);
    mCountTv = (TextView)findViewById(R.id.tv_count);
    mRootRl = (RelativeLayout)findViewById(R.id.rl_root);
  }

  private void initData(){
    mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
    mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
    mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
  }

  class GoodsAdapter extends RecyclerView.Adapter<GoodsViewHolder>{

    private List<Bitmap> mData;

    public GoodsAdapter(List<Bitmap> data) {
      mData = data;
    }

    @Override
    public GoodsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      View itemView = LayoutInflater.from(GoodsListActivity.this)
          .inflate(R.layout.rv_goods_item, parent, false);
      return new GoodsViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final GoodsViewHolder holder, int position) {
      holder.ivGood.setImageBitmap(mData.get(position));
      holder.tvBuy.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          addGoodToCar(holder.ivGood);
        }
      });
    }

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

  private void addGoodToCar(ImageView imageView){
    final ImageView view = new ImageView(GoodsListActivity.this);
    view.setImageDrawable(imageView.getDrawable());
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(100, 100);
    mRootRl.addView(view, layoutParams);

    //二、計算動畫開始/結束點的坐標的準備工作
    //得到父布局的起始點坐標(用于輔助計算動畫開始/結束時的點的坐標)
    int[] parentLoc = new int[2];
    mRootRl.getLocationInWindow(parentLoc);

    //得到商品圖片的坐標(用于計算動畫開始的坐標)
    int startLoc[] = new int[2];
    imageView.getLocationInWindow(startLoc);

    //得到購物車圖片的坐標(用于計算動畫結束后的坐標)
    int endLoc[] = new int[2];
    mCarImageView.getLocationInWindow(endLoc);

    float startX = startLoc[0] - parentLoc[0] + imageView.getWidth()/2;
    float startY = startLoc[1] - parentLoc[1] + imageView.getHeight()/2;

    //商品掉落后的終點坐標:購物車起始點-父布局起始點+購物車圖片的1/5
    float toX = endLoc[0] - parentLoc[0] + mCarImageView.getWidth() / 5;
    float toY = endLoc[1] - parentLoc[1];

    //開始繪制貝塞爾曲線
    Path path = new Path();
    path.moveTo(startX, startY);
    //使用二次薩貝爾曲線:注意第一個起始坐標越大,貝塞爾曲線的橫向距離就會越大,一般按照下面的式子取即可
    path.quadTo((startX + toX) / 2, startY, toX, toY);
    mPathMeasure = new PathMeasure(path, false);

    //屬性動畫
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
    valueAnimator.setDuration(1000);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float)animation.getAnimatedValue();
        mPathMeasure.getPosTan(value, mCurrentPosition, null);
        view.setTranslationX(mCurrentPosition[0]);
        view.setTranslationY(mCurrentPosition[1]);
      }
    });
    valueAnimator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {

      }

      @Override
      public void onAnimationEnd(Animator animation) {
        // 購物車的數(shù)量加1
        mCount++;
        mCountTv.setText(String.valueOf(mCount));
        // 把移動的圖片imageview從父布局里移除
        mRootRl.removeView(view);

        //shopImg 開始一個放大動畫
        Animation scaleAnim = AnimationUtils.loadAnimation(GoodsListActivity.this, R.anim.shop_car_scale);
        mCarImageView.startAnimation(scaleAnim);
      }

      @Override
      public void onAnimationCancel(Animator animation) {

      }

      @Override
      public void onAnimationRepeat(Animator animation) {

      }
    });
    valueAnimator.start();
  }

  class GoodsViewHolder extends RecyclerView.ViewHolder{

    private ImageView ivGood;
    private TextView tvBuy;

    public GoodsViewHolder(View itemView) {
      super(itemView);
      ivGood = (ImageView)itemView.findViewById(R.id.iv_goods);
      tvBuy = (TextView) itemView.findViewById(R.id.tv_buy);
    }
  }
}

關于“Android怎么實現(xiàn)購物車添加商品動畫”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI