仿饿了么添加购物车效果

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

最近有一个需求,要实现一个像饿了么添加购物车的效果,下面是效果图
主要有以下几点
  • 1 沉浸式状态栏

  • 2 上下滑动的动画

  • 3 添加减少的动画

  • 4 贝塞尔曲线动画

  • 5 底部购物车弹窗动画

  • 6 购物车缓存

沉浸式状态栏
沉浸式状态栏网上有很多,通常都是放v19和v21的包,然后在最外层ViewGroup设置fitsSystemWindows = "true" ,这种方式我不太推荐,因为你每次都要写fitsSystemWindows 这个属性,可能你会说我抽取出来不就好了,ok,那有时候要的效果不是我想要的,就比如我图上的效果,那怎么办呢,其实,有时候,你只需要一点小小的bang助!!!,几行代码的事

values

<style name="AppTheme.TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar"/>

values-v19

  <style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
  </style>

values-v21

 <style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">false</item>
        <item name="android:windowTranslucentNavigation">true</item>
        <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
        <item name="android:statusBarColor">@android:color/transparent</item>
 </style>
重头戏来了,以ToolBar为例,动态设置ToolBar的高度,并且设置一个padding,top为状态栏的高度,搞定收工!
  • activity
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            setHeight(mToolbar);
        }
    }

    public void setHeight(View view) {
        // 获取actionbar的高度
        TypedArray actionbarSizeTypedArray = obtainStyledAttributes(new int[]{
                android.R.attr.actionBarSize
        });
        float height = actionbarSizeTypedArray.getDimension(0, 0);
        // ToolBar的top值
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        double statusBarHeight = getStatusBarHeight(this);
        lp.height = (int) (statusBarHeight + height);
        view.setPadding(0,(int) statusBarHeight,0, 0);
        mToolbar.setLayoutParams(lp);
    }

    private double getStatusBarHeight(Context context) {
        int result = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
                "android");
        if (resourceId > 0) {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
  • xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    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:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:contentInsetStart="0dp"
    app:layout_collapseMode="pin">

    <FrameLayout
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize">

        <ImageView
            android:id="@+id/iv_back"
            android:layout_width="44dp"
            android:layout_height="44dp"
            android:layout_gravity="center_vertical"
            android:padding="14dp"
            android:src="@mipmap/icon_back"/>

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textColor="#ffffff"
            android:textSize="18sp"
            tools:text="Title"/>
    </FrameLayout>
</android.support.v7.widget.Toolbar>
下面是效果图
上下滑动的动画
没什么好说的,design包下的协调式布局(CoordinatorLayout),可以很好地实现这种效果,监听AppBarLayout的状态,打开的时候,隐藏标题,关闭的时候.显示标题,同时监听高度变化做透明度动画效果
  • XML布局
<android.support.design.widget.CoordinatorLayout
    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:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.activity.ShoppingGoodsActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:orientation="vertical">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@mipmap/icon_shopping_goods_bg"
            app:expandedTitleMarginStart="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:id="@+id/rl_header"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom">

                <ImageView
                    android:id="@+id/iv_goods_icon"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    android:layout_marginBottom="15dp"
                    android:layout_marginLeft="16dp"
                    android:src="@mipmap/ic_launcher"/>

                <TextView
                    android:id="@+id/tv_goods_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="115dp"
                    android:text="巴比馒头(四季店)"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp"/>

                <TextView
                    android:id="@+id/tv_goods_count"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignLeft="@id/tv_goods_title"
                    android:layout_below="@id/tv_goods_title"
                    android:layout_marginTop="1dp"
                    android:text="月销2390单"
                    android:textColor="#FFFFFF"
                    android:textSize="12sp"/>

                <TextView
                    android:id="@+id/tv_goods_address"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignLeft="@id/tv_goods_title"
                    android:layout_below="@id/tv_goods_count"
                    android:layout_marginTop="3dp"
                    android:text="上海市浦东新区东二环路与新海大道"
                    android:textColor="#FFFFFF"
                    android:textSize="12sp"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignLeft="@id/tv_goods_title"
                    android:layout_below="@id/tv_goods_address"
                    android:text="021-87689283"
                    android:textColor="#FFFFFF"
                    android:textSize="12sp"/>

                <LinearLayout
                    android:id="@+id/ll_discount_coupon"
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:layout_below="@id/iv_goods_icon"
                    android:background="#FFFFFF"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">

                    <ImageView
                        android:id="@+id/iv_discount_coupon"
                        android:layout_width="17dp"
                        android:layout_height="17dp"
                        android:layout_marginLeft="16dp"
                        android:src="@mipmap/icon_discount_coupon"/>

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="6dp"
                        android:text="5元优惠券"
                        android:textColor="#333333"
                        android:textSize="12sp"/>

                    <Space
                        android:layout_width="0dp"
                        android:layout_height="0dp"
                        android:layout_weight="1"/>

                    <TextView
                        android:id="@+id/tv_goods_get"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_marginRight="19dp"
                        android:gravity="center"
                        android:text="点击领取"
                        android:textColor="#BCBCBC"
                        android:textSize="12sp"/>
                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="9dp"
                    android:layout_below="@id/ll_discount_coupon"
                    android:background="#EFEFEF"/>
            </RelativeLayout>

            <include layout="@layout/layout_toolbar"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_goods"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="50dp"
        android:background="#ffffff"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

    <include
        android:id="@+id/layout_shopping_cart"
        layout="@layout/layout_shopping_cart"/>
</android.support.design.widget.CoordinatorLayout>
  • AppBarStateChangeListener
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {

    private State mCurrentState = State.IDLE;

    @Override
    public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        if (i == 0) {
            if (mCurrentState != State.EXPANDED) {
                onStateChanged(appBarLayout, State.EXPANDED);
            }
            mCurrentState = State.EXPANDED;
        } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
            if (mCurrentState != State.COLLAPSED) {
                onStateChanged(appBarLayout, State.COLLAPSED);
            }
            mCurrentState = State.COLLAPSED;
        } else {
            if (mCurrentState != State.IDLE) {
                onStateChanged(appBarLayout, State.IDLE);
            }
            mCurrentState = State.IDLE;
        }
        onStateChanged(i);
        Logger.d("滑动的的高度" + i);
    }

    public abstract void onStateChanged(AppBarLayout appBarLayout, State state);

    public void onStateChanged(int i) {
    }

    public enum State {
        EXPANDED,       // 展开状态
        COLLAPSED,      // 折叠状态
        IDLE            // 准备状态
    }
}
  • activity
private void initToolbar() {
        mAppBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
            @Override
            public void onStateChanged(AppBarLayout appBarLayout, State state) {
                if (state == State.EXPANDED) {
                    // 展开状态
                    mTvTitle.setText("");
                    mRlHeader.setVisibility(View.VISIBLE);
                } else if (state == State.COLLAPSED) {
                    // 折叠状态
                    mTvTitle.setText("芭比馒头");
                    mRlHeader.setVisibility(View.GONE);
                } else {
                    mTvTitle.setText("");
                    mRlHeader.setVisibility(View.VISIBLE);
                }
            }

            @Override
            public void onStateChanged(int i) {
                float height = mRlHeader.getHeight();
                float alpha = i / height;
                Logger.d("透明度" + (1 - Math.abs(alpha)));
                mRlHeader.setAlpha(1 - Math.abs(alpha));
            }
        });
    }
上面要注意的是,动态设置mRlHeader的显示隐藏,因为透明度有时候不为0的时候,还是会显示出来的
添加减少的动画
使用的是属性动画,单这里有一个坑,后面会讲到,尝试过用补间动画,但是由于补间动画的特性,本身的位置不变,达不到预期效果,有兴趣的可以尝试一下
  • 动画的代码
 public void animOpen(final ImageView imageView) {
        AnimatorSet animatorSet = new AnimatorSet();
        ObjectAnimator translationAnim = ObjectAnimator.ofFloat(imageView, "translationX", addLeft - reduceLeft, 0);
        ObjectAnimator rotationAnim = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180);
        animatorSet.play(translationAnim).with(rotationAnim);
        animatorSet.setDuration(TIME).start();
    }


 public void animClose(final ImageView imageView) {
        AnimatorSet animatorSet = new AnimatorSet();
        ObjectAnimator translationAnim = ObjectAnimator.ofFloat(imageView, "translationX", 0, addLeft - reduceLeft);
        ObjectAnimator rotationAnim = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180);
        animatorSet.play(translationAnim).with(rotationAnim);
        animatorSet.setDuration(TIME).start();
}
  • 动画打开还是关闭
        // 减少
        final ImageView iv_goods_reduce = holder.getView(R.id.iv_goods_reduce);
        iv_goods_reduce.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 获取减少图标的位置
                reduceLeft = iv_goods_reduce.getLeft();
                iv_goods_reduce.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
        iv_goods_reduce.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getLayoutPosition();
                ShopGoodsBean shopGoodsBean = mGoodsList.get(position);
                int count = shopGoodsBean.getCount();
                count--;
                // 防止过快点击出现多个关闭动画
                if (count == 0) {
                    animClose(iv_goods_reduce);
                    tv_goods_count.setText("");
                    // 考虑到用户点击过快
                    allCount--;
                } else if (count < 0) {
                    // 防止过快点击出现商品数为负数
                    count = 0;
                } else {
                    allCount--;
                    tv_goods_count.setText(String.valueOf(count));
                }
                // 商品的数量是否显示
                if (allCount <= 0) {
                    allCount = 0;
                    mTvShoppingCartCount.setVisibility(View.GONE);
                } else {
                    mTvShoppingCartCount.setText(String.valueOf(allCount));
                    mTvShoppingCartCount.setVisibility(View.VISIBLE);
                }
                shopGoodsBean.setCount(count);
            }
        });
// 增加
        final ImageView iv_goods_add = holder.getView(R.id.iv_goods_add);
        iv_goods_add.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 获取增加图标的位置
                addLeft = iv_goods_add.getLeft();
                iv_goods_add.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
        iv_goods_add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getLayoutPosition();
                ShopGoodsBean shopGoodsBean = mGoodsList.get(position);
                int count = shopGoodsBean.getCount();
                count++;
                allCount++;
                if (allCount > 0) {
                    mTvShoppingCartCount.setVisibility(View.VISIBLE);
                }
                mTvShoppingCartCount.setText(String.valueOf(allCount));![1.gif](https://upload-images.jianshu.io/upload_images/5286943-8616ee25e4dd2edc.gif?imageMogr2/auto-orient/strip)

                if (count == 1) {
                    iv_goods_reduce.setVisibility(View.VISIBLE);
                    animOpen(iv_goods_reduce);
                }
                addGoods2CartAnim(iv_goods_add);
                tv_goods_count.setText(String.valueOf(count));
                shopGoodsBean.setCount(count);
            }
        });
通过getViewTreeObserver获取图标的位置,计算距离,做属性动画,同时通过数据层记录,要注意的是,如果手指点击点击过快的时候,会使减少的变为负数,所以我们要做判断,如果为0不减少
你可以看到,减少的图标不见了,而且点击也没效果,很简单,主要是RecycleView的item复用机制,属性动画改变控件位置,所以做完动画位置还原就好了
public void animClose(final ImageView imageView) {
        AnimatorSet animatorSet = new AnimatorSet();
        ObjectAnimator translationAnim = ObjectAnimator.ofFloat(imageView, "translationX", 0, addLeft - reduceLeft);
        ObjectAnimator rotationAnim = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180);
        animatorSet.play(translationAnim).with(rotationAnim);
        animatorSet.setDuration(TIME).start();
        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // TODO: 2018/5/19 因为属性动画会改变位置,所以当结束的时候,要回退的到原来的位置,同时用补间动画的位移不好控制
                ObjectAnimator oa = ObjectAnimator.ofFloat(imageView, "translationX", addLeft - reduceLeft, 0);
                oa.setDuration(0);
                oa.start();
                imageView.setVisibility(View.GONE);
            }
        });
    }

4 贝塞尔曲线动画

一个二阶贝塞尔动画,没有涉及到动态点,比较简单,在你点击的时候,在最外层布局添加一个ImageView,做值动画,动画结束的时候,移除该控件
/**
     * 贝塞尔曲线动画
     *
     * @param goodsImageView
     */
    public void addGoods2CartAnim(ImageView goodsImageView) {
        final ImageView goods = new ImageView(ShoppingGoodsActivity.this);
        goods.setImageResource(R.mipmap.icon_goods_add);
        int size = Util.dp2px(ShoppingGoodsActivity.this, 24);
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(size, size);
        goods.setLayoutParams(lp);
        mCoordinatorLayout.addView(goods);
        // 控制点的位置
        int[] recyclerLocation = new int[2];
        mCoordinatorLayout.getLocationInWindow(recyclerLocation);
        // 加入点的位置起始点
        int[] startLocation = new int[2];
        goodsImageView.getLocationInWindow(startLocation);
        // 购物车的位置终点
        int[] endLocation = new int[2];
        mIvShoppingCart.getLocationInWindow(endLocation);
        // TODO: 2018/5/21 0021 考虑到状态栏的问题,不然会往下偏移状态栏的高度
        int startX = startLocation[0] - recyclerLocation[0];
        int startY = startLocation[1] - recyclerLocation[1];
        // TODO: 2018/5/21 0021 和上面一样
        int endX = endLocation[0] - recyclerLocation[0];
        int endY = endLocation[1] - recyclerLocation[1];
        // 开始绘制贝塞尔曲线
        Path path = new Path();
        // 移动到起始点位置(即贝塞尔曲线的起点)
        path.moveTo(startX, startY);
        // 使用二阶贝塞尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的式子取即可
        path.quadTo((startX + endX) / 2, startY, endX, endY);
        // mPathMeasure用来计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标,如果是true,path会形成一个闭环
        final PathMeasure pathMeasure = new PathMeasure(path, false);
        // 属性动画实现(从0到贝塞尔曲线的长度之间进行插值计算,获取中间过程的距离值)
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength());
        // 计算距离
        int tempX = Math.abs(startX - endX);
        int tempY = Math.abs(startY - endY);
        // 根据距离计算时间
        int time = (int) (0.3 * Math.sqrt((tempX * tempX) + tempY * tempY));
        valueAnimator.setDuration(time);
        valueAnimator.start();
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 当插值计算进行时,获取中间的每个值,
                // 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)
                float value = (Float) animation.getAnimatedValue();
                // 获取当前点坐标封装到mCurrentPosition
                // boolean getPosTan(float distance, float[] pos, float[] tan) :
                // 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。
                // mCurrentPosition此时就是中间距离点的坐标值
                pathMeasure.getPosTan(value, mCurrentPosition, null);
                // 移动的商品图片(动画图片)的坐标设置为该中间点的坐标
                goods.setTranslationX(mCurrentPosition[0]);
                goods.setTranslationY(mCurrentPosition[1]);
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // 移除图片
                mCoordinatorLayout.removeView(goods);
                // 购物车数量增加
                mTvShoppingCartCount.setText(String.valueOf(allCount));
            }
        });
    }

5 底部购物车弹窗动画

底部的一个动画效果,大致原理就是,用一个FrameLayout,底部保持不动,上面的ViewGroup做位移动画,同时判断商品个数,动态控制RecycleView的高度
  • 动态设置RecycleView的高度
private void initAdapter() {
        // 如果商品个数大于指定数时,高度写死,其他wrap_content
        if (list.size() >= 4) {
            ViewGroup.LayoutParams lp = mRvCartGoods.getLayoutParams();
            lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
            lp.height = DensityUtil.dp2px(200);
            mRvCartGoods.setLayoutParams(lp);
        }
        mAdapter = new BaseAdapter(list, R.layout.item_cart_goods, this);
        mRvCartGoods.setLayoutManager(new LinearLayoutManager(mActivity));
        mRvCartGoods.setAdapter(mAdapter);
    }
网上找过很多设置最大值的,都没有效果,后面直接改用代码动态设置
  • 动画效果
private void initScreen() {
        WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(dm);
        // 获取屏幕的高度
        mHeightPixels = dm.heightPixels;
    }

    public void openAnim() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mLlShoppingCart, "translationY", mHeightPixels, 0);
        objectAnimator.setDuration(TIME);
        objectAnimator.start();
    }

    public void closeAnim() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mLlShoppingCart, "translationY", 0, mHeightPixels);
        objectAnimator.setDuration(TIME);
        objectAnimator.start();
        objectAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                dismiss();
            }
        });
    }
可以看到,在关闭的时候做了一个动画监听,直接调用dismiss()方法,会直接销毁掉,我们要等到动画执行完毕之后在销毁掉
购物车缓存
storeId为文件名,同时内部用一个map集合储存数据,key为goodsID,value为count,allCount为商铺总数
    /**
   * 添加商品缓存
   *
   * @param storeId 商品的id
   */
  public ShoppingCartHistoryManager add(String storeId, @NonNull StoreGoodsBean storeGoodsBean) {
    File file = new File(PATH);
    if (!file.exists()) {
      file.mkdirs();
    }
    FileOutputStream fileOutputStream = null;
    ObjectOutputStream objectOutputStream = null;
    try {
      fileOutputStream = new FileOutputStream(file.getAbsolutePath() + File.separator + storeId + FILE_FORMAT);
      objectOutputStream = new ObjectOutputStream(fileOutputStream);
      objectOutputStream.writeObject(storeGoodsBean);
      objectOutputStream.flush();
      objectOutputStream.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return this;
  }

  /**
   * 得到商品缓存
   *
   * @param storeId 商铺的id
   */
  public HashMap<String, Integer> get(String storeId) {
    File file = new File(PATH);
    if (!file.exists()) {
      return null;
    }
    FileInputStream FileInputStream = null;
    ObjectInputStream objectInputStream = null;
    StoreGoodsBean storeGoodsBean = null;
    try {
      FileInputStream = new FileInputStream(file.getAbsolutePath() + File.separator + storeId + FILE_FORMAT);
      objectInputStream = new ObjectInputStream(FileInputStream);
      storeGoodsBean = (StoreGoodsBean) objectInputStream.readObject();
      objectInputStream.close();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
    return storeGoodsBean.getHashMap();
  }

  /**
   * 获取商铺选择的总个数
   *
   * @param storeId 商铺id
   * @return
   */
  public int getAllGoodsCount(String storeId) {
    HashMap<String, Integer> hashMap = get(storeId);
    int allCount = 0;
    if (hashMap != null) {
      for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
        Integer value = entry.getValue();
        if (value != 0) {
          allCount += value;
        }
      }
    }
    return allCount;
  }

  /**
   * 删除商铺缓存,如果数量为0
   *
   * @param storeId 商铺的id
   */
  public ShoppingCartHistoryManager delete(@NonNull String storeId) {
    File file = new File(PATH, storeId + FILE_FORMAT);
    if (file.exists()) {
      file.delete();
    }
    return this;
  }

    /**
     * 删除商铺缓存,如果数量为0
     *
     * @param ShopId 商铺的id
     */
    public ShoppingCartHistoryManager delete(@NonNull int ShopId) {
        File file = new File(PATH, +ShopId + FILE_FORMAT);
        if (file.exists()) {
            file.delete();
        }
        return this;
    }
退出页面时,根据商铺的总数是否为0,选择删除数据(如果文件之前存在)还是保存数据
 @Override
    protected void onDestroy() {
        super.onDestroy();
        if (allCount != 0) {
            HashMap<String, Integer> hashMap = new HashMap<>();
            StoreGoodsBean storeGoodsBean = new StoreGoodsBean(hashMap);
            for (ShopGoodsBean bean : mGoodsList) {
                int count = bean.getCount();
                String goodsId = bean.getGoodsId();
                if (count != 0) {
                    hashMap.put(goodsId, count);
                }
            }
            ShoppingCartHistoryManager.getInstance().add(SHOP_ID, storeGoodsBean);
        } else {
            ShoppingCartHistoryManager.getInstance().delete(SHOP_ID);
        }
    }
进入页面的时候,获取缓存数据(如果存在)
private void initData() {
        int id = 0x100;
        HashMap<String, Integer> hashMap = ShoppingCartHistoryManager.getInstance().get(SHOP_ID);
        this.allCount = ShoppingCartHistoryManager.getInstance().getAllGoodsCount(SHOP_ID);
        showToast("商品总数" + allCount);
        // 根据缓存是否显示
        mTvShoppingCartCount.setVisibility(allCount == 0 ? View.GONE : View.VISIBLE);
        mTvShoppingCartCount.setText(String.valueOf(allCount));
        // TODO: 2018/6/5 0005 模拟请求到的数据
        for (int i = 0; i < 10; i++) {
            mGoodsList.add(new ShopGoodsBean(0, "小猪包套餐" + i, id++ + ""));
        }
        if (hashMap != null) {
            for (ShopGoodsBean bean : mGoodsList) {
                String goodsId = bean.getGoodsId();
                if (hashMap.containsKey(goodsId)) {
                    Integer count = hashMap.get(goodsId);
                    bean.setCount(count);
                }
            }
        }
    }
在最外面的商铺列表通过storeId获取商铺总数
this.allCount =ShoppingCartHistoryManager.getInstance().getAllGoodsCount(SHOP_ID);
github:https://github.com/GongWnbo/SuperRecycleView
有疑问,不足的地方,或更好的方式,请以留言的方式告知,如果觉得不错就顺手给个Star![]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容