Android实现购物车添加商品动画

所属分类: 软件编程 / Android 阅读数: 42
收藏 0 赞 0 分享

本文实例为大家分享了Android实现购物车添加商品动画的具体代码,供大家参考,具体内容如下

实现需求:

在商品列表页面,从列表Item 添加商品的时候,需要一个动画,仿佛是是往购物车里添加商品。

实现思路:

  1. 获取起始点与终点的坐标,利用PathMeasure 绘制贝塞尔曲线;
  2. 为点击的Item 商品View 设置属性动画;
  3. 监听属性动画的update,改变View 的坐标;

实现效果:

实现中会用到 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);//系统调用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() 之间的值,根据这个值 PathMeasure 会计算出当前点的坐标封装到 pos 中。上面这句话我们可以这么来理解,不管实际 Path 多么的复杂,PathMeasure 都相当于做了一个事情,就是把 Path “拉直”,然后给了我们一个接口(getLength)告诉我们path的总长度,然后我们想要知道具体某一点的坐标,只需要用相对的distance去取即可,这样就省去了自己用函数模拟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) {
        // 购物车的数量加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);
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

使用ViewPager实现android软件使用向导功能实现步骤

现在的大部分android软件,都是使用说明,就是第一次使用该软件时,会出现向导,可以左右滑动,然后就进入应用的主界面了,下面我们就实现这个功能
收藏 0 赞 0 分享

android在异步任务中关闭Cursor的代码方法

android在异步任务中如何关闭Cursor?在我们开发应用的时候,很多时候会遇到这种问题,下面我们就看看代码如何实现
收藏 0 赞 0 分享

Android自定义桌面功能代码实现

android自定义桌面其实很简单,看一个例子就明白了
收藏 0 赞 0 分享

android将图片转换存到数据库再从数据库读取转换成图片实现代码

有时候我们想把图片存入到数据库中,尽管这不是一种明智的选择,但有时候还是不得以会用到,下面说说将图片转换成byte[]数组存入到数据库中去,并从数据库中取出来转换成图像显示出来
收藏 0 赞 0 分享

TextView显示系统时间(时钟功能带秒针变化

用System.currentTimeMillis()可以获取系统当前的时间,我们可以开启一个线程,然后通过handler发消息,来实时的更新TextView上显示的系统时间,可以做一个时钟的功能
收藏 0 赞 0 分享

Android用ListView显示SDCard文件列表的小例子

本文简单实现了用ListView显示SDCard文件列表,目录的回退等功能暂不讨论,获取文件列表,files即为所选择目录下的所有文件列表
收藏 0 赞 0 分享

Android拦截外拨电话程序示例

这篇文章主要介绍了Android拦截外拨电话的示例,大家参考使用吧
收藏 0 赞 0 分享

通过Html网页调用本地安卓(android)app程序代码

如何使用html网页和本地app进行传递数据呢?经过研究,发现还是有方法的,总结了一下,大致有一下几种方式
收藏 0 赞 0 分享

android Textview文字监控(Textview使用方法)

以手机号充值为例,当用户输入最后一位数时候,进行汇率的变换,本文就实现类似这样的功能
收藏 0 赞 0 分享

Android ListView长按弹出菜单二种实现方式示例

这篇文章主要介绍了Android ListView长按弹出菜单的方法,大家参考实现
收藏 0 赞 0 分享
查看更多