实现美团、饿了么购物车效果,并本地存储相关数据

前言

圣诞节快到了,在这里先祝大家圣诞节快乐!这里写图片描述
这篇文章就当我送给大家的节日礼物了(可能写的博客技术含量不是很高或者有些许错误,希望大家谅解)。

效果图

这里写图片描述

分析

有很多时候我们会得到各式各样的效果和功能,在了解了任务之后我不建议大家马上去百度或者编写代码。应该先分析任务的逻辑,并思考每部分利用什么控件或者技术实现,哪种实现效果能使我们的逻辑更清晰,即使代码编写错误当我们修改的时候也不需要改动太大或者重新进行编写(遵循开闭原则),避免浪费我们的时间。其实就是我们面向接口编程的思想,先抽象后实现。

  1. 对于左侧菜单和右侧内容部分联动的效果——采用两个RecyclerView控件
  2. 添加购物车动画的实现——采用TranslateAnimation动画
  3. 数据的存储、获取以及删除——采用xutils框架

是不是感觉简单分析之后,思路清晰多了,实现起来也知道该从哪里入手了。

代码实现

1. RecyclerView控件实现左侧菜单和右侧内容联动效果

activity_main.xml

<LinearLayout
    android:layout_below="@+id/include"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/view"
    android:orientation="horizontal">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/m_list_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="5"
        android:scrollbars="none">

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/m_list_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:scrollbars="none">

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

主布局相对来说简单多了,就不进行详细的讲解了。

item_menu.xml

<LinearLayout
    android:id="@+id/black_lay"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:orientation="horizontal">
    <View
        android:id="@+id/item_menu_view_red"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:layout_weight="30"
        android:background="@color/title_color_ff0000"/>
    <TextView
        android:id="@+id/item_menu_text"
        android:layout_width="match_parent"
        android:gravity="center_horizontal"
        android:layout_height="wrap_content"
        android:layout_weight="0.5"
        android:textSize="16sp"
        android:textColor="@android:color/black"
        android:text="好评榜"/>
    <View
        android:id="@+id/item_menu_view_v"
        android:layout_width="0.1dp"
        android:layout_height="50dp"
        android:background="@color/color_menu_lines"/>
</LinearLayout>

菜单布局左右两侧分别有一条竖着的黑线和红线,当我们进行点击item操作的时候,需要进行的隐藏和显示效果来达到该item处于选中状态。

item_menu_content.xml

item_menu_content就是一个简单的布局,由于代码量太大就不进行展示了,大家可以下载我的Demo进行查看。

RecyclerViewMenuAdapter.java

左侧菜单的数据填充器,主要的部分就是在onBindViewHolder方法里面,先让所有的item显示为默认状态,在根据点击item对应的position来改变该item的状态即可:

//绑定ViewHolder
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    holder.mTextView.setText(DemoData.ListMenu_STYLE[position]);
    //设置所有的item显示为默认状态
    holder.mLinearLayout.setBackgroundResource(R.color.color_menu_back);
    holder.viewRed.setVisibility(View.GONE);
    holder.viewV.setVisibility(View.VISIBLE);
    //根据点击item对应的position来改变该item的状态
    if (holder.getPosition() == MainActivity.SELECTPOSITION) {
        holder.mLinearLayout.setBackgroundResource(R.color.white);
        holder.viewRed.setVisibility(View.VISIBLE);
        holder.viewV.setVisibility(View.GONE);
    }
    setOnListtener(holder);
}

RecyclerViewContentAdapter.java

左侧内容填充器则为普通的内容没有什么特殊的地方

MainActivity.java

/**
 * 菜单列表    数据填充
 */
private void setMenuCommonadapter() {
     mRecyclerViewMenuCommonadapter = new RecyclerViewMenuAdapter(mContext, stringMenuList);
     mRecyclerMenu.setAdapter(mRecyclerViewMenuCommonadapter);
     mRecyclerViewMenuCommonadapter.setOnItemClickListener(new RecyclerViewMenuAdapter.OnItemClickListener() {
         @Override
         public void onItemClick(View v, int position) {
             SELECTPOSITION = position;
             Log.e("TAG", "SELECTPOSITION:" + SELECTPOSITION);
             mRecyclerViewMenuCommonadapter.notifyDataSetChanged();
             mRecyclerViewContentCommonadapter.notifyDataSetChanged();
         }
         @Override
         public void onItemLongClick(View v, int position) {}
     });
}

当点击item的时候,改变SELECTPOSITION 的值,再刷新两个recyclerview即可。

效果图如下:

这里写图片描述

由于数据全部都是一样的所以可能看起来,左侧内容部分没有什么改变,但其实数据已经刷新了。
模拟器和录制gif图工具有些问题,所以分割线显示不全并且有色差,大家如果有什么好的工具可以给我推荐推荐,在这里谢谢大家了!

2.添加购物车动画的实现

在做添加购物车动画的时候,首先想到的就是translateanimation平移动画,公司同事做过类似的动画所以拿过来稍加修改并封装成了工具类,使用起来杠杠滴。

/** 动画 */
GoodsAnimUtil.setAnim(MainActivity.this, holder.mImgJia, mCarLay);
GoodsAnimUtil.setOnEndAnimListener(new onEndAnim());

首先调用工具类里面的setAnim()方法,就可以设置和开始动画了;
再监听动画,当动画结束时进行相关操作即可。

public static void setAnim(Activity activity , View imgphoto, View imgcar){
     mActivity = activity;
     mImgcar = imgcar;
     // 一个整型数组,用来存储按钮的在屏幕的X、Y坐标
     int[] start_location = new int[2];
     // 这是获取购买按钮的在屏幕的X、Y坐标(这也是动画开始的坐标)
     imgphoto.getLocationInWindow(start_location);
     int[] start_location1 = new int[]{start_location[0], start_location[1]};
     // buyImg是动画的图片,我的是一个小球(R.drawable.sign)
     ImageView buyImg = new ImageView(mActivity);
     // 设置buyImg的图片
     buyImg.setImageResource(R.mipmap.aii);
     // 开始执行动画
     startAnim(buyImg, start_location1);
}
  • imgphoto代表我们点击的view,通过imgphoto.getLocationInWindow(start_location)得带我们点击view的横坐标和纵坐标,并存在start_location数组里面;
  • imgcar代表结束位置的view,也是通过mImgcar.getLocationInWindow(end_location)得到结束位置的横坐标和纵坐标,并存在end_location数组里面。
/**
 *开始动画
 */
private static void startAnim(final View v, int[] start_location) {
    anim_mask_layout = null;
    anim_mask_layout = createAnimLayout();
    anim_mask_layout.addView(v);//把动画小球添加到动画层
    view = addViewToAnimLayout(anim_mask_layout, v,start_location);
    int[] end_location = new int[2];// 这是用来存储动画结束位置的X、Y坐标
    mImgcar.getLocationInWindow(end_location);// shopCart是那个购物车
    int width = getWindowsWidth(mActivity);
    // 计算位移
    int endY = end_location[1] - start_location[1];// 动画位移的y坐标
    int endX = 0 - start_location[0] + (mImgcar.getWidth() / 2);// 动画位移的X坐标
    TranslateAnimation translateAnimationX = new TranslateAnimation(0,endX, 0, 0);
    translateAnimationX.setInterpolator(new LinearInterpolator());
    translateAnimationX.setRepeatCount(0);// 动画重复执行的次数
    translateAnimationX.setFillAfter(true);
    TranslateAnimation translateAnimationY = new TranslateAnimation(0, 0,0, endY);
    translateAnimationY.setInterpolator(new AccelerateInterpolator());
    translateAnimationY.setRepeatCount(0);// 动画重复执行的次数
    translateAnimationX.setFillAfter(true);
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.3f, 1.0f, 0.3f);
    scaleAnimation.setInterpolator(new AccelerateInterpolator());
    scaleAnimation.setRepeatCount(0);// 动画重复执行的次数
    scaleAnimation.setFillAfter(true);
    scaleAnimation.setDuration(300);
    final AnimationSet set = new AnimationSet(false);
    set.setFillAfter(false);
    set.addAnimation(translateAnimationY);
    set.addAnimation(translateAnimationX);
    //set.setStartOffset(300);
    set.setDuration(800);// 动画的执行时间
    view.startAnimation(set);
    // 动画监听事件
    set.setAnimationListener(new Animation.AnimationListener() {
        // 动画的开始
        @Override
        public void onAnimationStart(Animation animation) {
            v.setVisibility(View.VISIBLE);
        }
        @Override
        public void onAnimationRepeat(Animation animation) {}
        // 动画的结束
        @Override
        public void onAnimationEnd(Animation animation) {
            v.setVisibility(View.GONE);
            anim_mask_layout.removeAllViews();
            YoYo.with(Techniques.Bounce).withListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {}
                @Override
                public void onAnimationEnd(Animator animation) {
                    mEndAnimListener.onEndAnim();
                }
                @Override
                public void onAnimationCancel(Animator animation) {}
                @Override
                public void onAnimationRepeat(Animator animation) {}
            }).interpolate(new BounceInterpolator()).duration(400).playOn(mImgcar);
        }
    });
}

在这堆复杂的代码中,我们只需要关心这两句代码即可:

// 计算位移
int endY = end_location[1] - start_location[1];// 动画位移的y坐标
int endX = end_location[0] - start_location[0] + (mImgcar.getWidth() / 2);// 动画位移的X坐标

在我们的手机界面里,左上角为(0,0),所以从上向下是正,从左向右是正,所以:
结束位置的纵坐标减去开始位置的纵坐标作为动画位移的y距离;
结束位置的横坐标减去开始位置的横坐标再加上结束位置的view的一半作为动画移动的x距离。

动画效果就实现了,当然如果你想实现其他效果只需要修改GoodsAnimUtil类即可,而主代码中的代码不需要改变,这就体现出了低耦合的重要性;

3.采用xutils框架实现本地数据库

GoodsBean .java

@Table(name = "goods")
public class GoodsBean extends GoodsBase{
    @Column(column = "menupos")
    private int menupos;
    @Column(column = "goodsid")
    private int goodsid;
    @Column(column = "goodsnum")
    private String goodsnum;
    @Column(column = "goodsprice")
    private String goodsprice;

    public int getMenupos() {
        return menupos;
    }

    public void setMenupos(int menupos) {
        this.menupos = menupos;
    }

    public int getGoodsid() {
        return goodsid;
    }

    public void setGoodsid(int goodsid) {
        this.goodsid = goodsid;
    }

    public String getGoodsnum() {
        return goodsnum;
    }

    public void setGoodsnum(String goodsnum) {
        this.goodsnum = goodsnum;
    }

    public String getGoodsprice() {
        return goodsprice;
    }

    public void setGoodsprice(String goodsprice) {
        this.goodsprice = goodsprice;
    }

    @Override
    public String toString() {
        return "GoodsBean{" +
                "menupos='" + menupos + '\'' +
                ", goodsid='" + goodsid + '\'' +
                ", goodsnum='" + goodsnum + '\'' +
                ", goodsprice='" + goodsprice + '\'' +
                '}';
    }
}

新建数据库goods,菜单栏每项对应的menupos、商品的goodsid、存储数量goodsnum和每个商品对应的价格goodsprice这几个字段是我们在进行数据库操作的时候需要使用到的字段;

分析效果图:

a.点击加号,根据菜单栏的menupos和对应的商品的goodsid进行存储数据;
b.点击减号,根据菜单栏的menupos和对应的商品的goodsid进行存储数据;
c.点击菜单栏的item,根据菜单栏的menupos得到二级每个商品已经存储的数量;
d.点击菜单栏的item,根据菜单栏的menupos得到二级所有商品的存储数量;
e.点击菜单栏的item,根据菜单栏的menupos得到二级所有商品的存储价格;
f.删除所有的存储数据。

根据分析结果,编写接口以及我们需要实现的方法:

GoodsDataBaseInterface .java

public interface GoodsDataBaseInterface {
    /** 添加和删除购物的数量 */
    int saveGoodsNumber(Context context, int menupos, int goodsid, String goodsnum, String goodsprice);

    /** 根据下标得到 第二级对应购物的数量 */
    int getSecondGoodsNumber(Context context, int menupos, int goodsid);

    /** 根据第一级的下标 得到第二级的所有购物数量 */
    int getSecondGoodsNumberAll(Context context, int menupos);

    /** 根据第一级的下标 得到第二级的所有购物的价格 */
    int getSecondGoodsPriceAll(Context context, int menupos);
    /** 删除所有的购物数据 */
    void deleteAll(Context context);

}

编写实现类OperateGoodsDataBase继承GoodsDataBaseInterface 接口:

public class OperateGoodsDataBase implements GoodsDataBaseInterface{
   private static OperateGoodsDataBase instance  = new OperateGoodsDataBase();
   public static OperateGoodsDataBase getInstance(){
       return  instance;
   }
   private OperateGoodsDataBase(){}
   /**
    *添加和删除商品数量,并得到商品数量
    */
   @Override
   public int saveGoodsNumber(Context context, int menupos, int goodsid, String goodsnum , String goodsprice) {
       return OperateGoodsDataBaseStatic.saveGoodsNumber(context , menupos , goodsid , goodsnum ,goodsprice);
   }
   /**
    *根据下标得到 第二级对应购物的数量
    */
   @Override
   public int getSecondGoodsNumber(Context context, int menupos, int goodsid) {
       return OperateGoodsDataBaseStatic.getSecondGoodsNumber(context, menupos, goodsid);
   }
   /**
    * 根据第一级的下标 得到第二级的所有购物数量
    */
   @Override
   public int getSecondGoodsNumberAll(Context context, int menupos) {
       return OperateGoodsDataBaseStatic.getSecondGoodsNumberAll(context, menupos);
   }

   /**
    *据第一级的下标 得到第二级的所有购物的价格
    */
   @Override
   public int getSecondGoodsPriceAll(Context context, int menupos) {
       return OperateGoodsDataBaseStatic.getSecondGoodsPriceAll(context, menupos);
   }
   /**
    *删除所有的购物数据
    */
   @Override
   public void deleteAll(Context context) {
       OperateGoodsDataBaseStatic.deleteAll(context);
   }
}

在实现类里面写了一个单例,这样在其他类里面调用该单例只会有一个实现类,减少了内存的消耗;

OperateGoodsDataBaseStatic.java

public class OperateGoodsDataBaseStatic{
    /**
     *添加和删除商品数量
     */
    public static int saveGoodsNumber(Context context, int menupos, int goodsid, String goodsnum , String goodsprice) {
        DbUtils utils = DbUtils.create(context);
        GoodsBean goodsBean = null;
        goodsBean =new GoodsBean();
        goodsBean.setMenupos(menupos);
        goodsBean.setGoodsid(goodsid);
        goodsBean.setGoodsnum(goodsnum);
        goodsBean.setGoodsprice(goodsprice);
        try {
            GoodsBean bean = utils.findFirst(Selector.from(GoodsBean.class).where("menupos" , "=" , menupos).and("goodsid", "=", goodsid));
            //如果有这条数据,数量直接加1;否则就插入表里面
            if(bean == null){
                Log.e("TAG", "还没有该商品");
                utils.save(goodsBean);
                Log.e("TAG" , "该商品已经存储");
                return getSecondGoodsNumber(context , menupos , goodsid);
            }else{
                Log.e("TAG" , "已经有该商品");
                //返回添加商品之后的商品总数
                return updateNum(context, menupos, goodsid, goodsnum);
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        Log.e("TAG" , "添加商品失败");
        utils.close();
        return 0;
    }
    /**修改数量,直接传入数量**/
    public static int updateNum(Context context , int menupos , int goodsid , String goodsnum){
        DbUtils utils = DbUtils.create(context);
        try {
            GoodsBean bean = utils.findFirst(Selector.from(GoodsBean.class).where("menupos", "=", menupos).and("goodsid", "=", goodsid));
            bean.setGoodsnum(goodsnum);
            utils.update(bean);
            Log.e("TAG", "该商品数量改变为:" + getSecondGoodsNumber(context, menupos, goodsid));
            return getSecondGoodsNumber(context , menupos , goodsid);
        } catch (DbException e) {
            e.printStackTrace();
        }
        utils.close();
        return 0;
    }
    /**
     *根据下标得到 第二级对应购物的数量
     */
    public static int getSecondGoodsNumber(Context context , int menupos , int goodsid) {
        DbUtils utils = DbUtils.create(context);
        if(utils == null){
            Log.e("TAG" , "还没有该数据库");
            return 0;
        }
        try {
            GoodsBean bean = utils.findFirst(Selector.from(GoodsBean.class).where("menupos", "=", menupos).and("goodsid", "=", goodsid));
            if(bean == null){
                Log.e("TAG" , "还没有该存储商品");
                return 0;
            }else{
                Log.e("TAG" , "获取商品数量成功:" + Integer.parseInt(bean.getGoodsnum()));
                return Integer.parseInt(bean.getGoodsnum());
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        utils.close();
        Log.e("TAG", "获取商品数量失败");
        return 0;
    }
    /**
     * 根据第一级的下标 得到第二级的所有购物数量
     */
    public static int getSecondGoodsNumberAll(Context context, int menupos) {
        DbUtils utils = DbUtils.create(context);
        int mSecondGoodsNum = 0;
        ArrayList<GoodsBean> mGoodsBeanList = null;
        mGoodsBeanList = getSecondGoodsTypeList(context);
        if(mGoodsBeanList == null){
            Log.e("TAG" , "获取商品类型总数失败");
            return 0;
        }
        for(int i = 0 ; i < mGoodsBeanList.size() ; i++){
            if(mGoodsBeanList.get(i).getMenupos() == menupos){
                mSecondGoodsNum += Integer.parseInt(mGoodsBeanList.get(i).getGoodsnum());
            }
        }
        Log.e("TAG", "根据第一级的下标 得到第二级的所有购物数量成功:" + mSecondGoodsNum);
        utils.close();
        return mSecondGoodsNum;
    }
    /**
     *根据第一级的下标 得到第二级商品所有商品类型集合
     */
    public static ArrayList<GoodsBean> getSecondGoodsTypeList(Context context){
        DbUtils utils = DbUtils.create(context);
        ArrayList<GoodsBean> list = null;
        try {
            list = (ArrayList<GoodsBean>) DbUtils.create(context).findAll(GoodsBean.class);
            if(list == null){
                Log.e("TAG" , "该二级商品还没有存储数据");
                return null;
            }else{
                Log.e("TAG" , "根据第一级的下标 得到第二级商品类型总数成功:" + list.size());
                return list;
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        Log.e("TAG" , "根据第一级的下标 得到第二级商品类型总数失败");
        return null;
    }

    /**
     *据第一级的下标 得到第二级的所有购物的价格
     */
    public static int getSecondGoodsPriceAll(Context context, int menupos) {
        DbUtils utils = DbUtils.create(context);
        int mSecondGoodsPrice = 0;
        ArrayList<GoodsBean> mGoodsBeanList = null;
        mGoodsBeanList = getSecondGoodsTypeList(context);
        if(mGoodsBeanList == null){
            Log.e("TAG" , "获取商品类型总数失败");
            return 0;
        }
        for(int i = 0 ; i < mGoodsBeanList.size(); i++){
            if(mGoodsBeanList.get(i).getMenupos() == menupos){
                mSecondGoodsPrice += Integer.parseInt(mGoodsBeanList.get(i).getGoodsnum()) * Integer.parseInt(mGoodsBeanList.get(i).getGoodsprice());
            }
        }
        Log.e("TAG" , "根据第一级的下标 得到第二级的所有购物的价格成功:" + mSecondGoodsPrice);
        utils.close();
        Log.e("TAG" , "根据第一级的下标 得到第二级的所有购物的价格失败");
        return mSecondGoodsPrice;
    }
    /**
     *删除所有的购物数据
     */
    public static void deleteAll(Context context) {
        DbUtils utils = DbUtils.create(context);
        try {
            List<GoodsBean> records = utils.findAll(GoodsBean.class);
            utils.deleteAll(records);
        } catch (DbException e) {
            e.printStackTrace();
        }
        utils.close();
    }
}

对于数据库的操作,没有什么复杂的逻辑,只需要记住基本的代码就可以了,所以就不进行讲解了,里面备注写的也十分详细;

整合代码

RecyclerViewContentAdapter.java

a.在onBindViewHolder()方法里面根据点击的一级菜单的position和商品id,判断数据库里面是否有该商品,有该商品则显示减号图标和对应的存储数量;

//绑定ViewHolder
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    holder.mImageView.setImageResource(DemoData.ListMenu_PIMAGES[position]);
    holder.mTitle.setText(DemoData.ListMenu_PTITLE[position]);
    holder.mYueSale.setText("月售" + DemoData.ListMenu_NUMBER[position]);
    holder.mPrice.setText(DemoData.ListMenu_PPRICE[position]);

    holder.mRatingBar.setRating(Float.parseFloat(DemoData.ListMenu_STAR[position]));
    holder.mRatingBar.getRating();

    /** 获取存储的商品数量 */
    if (mGoodsDataBaseInterface.getSecondGoodsNumber(mContext, MainActivity.SELECTPOSITION , DemoData.ListMenu_GOODSID[holder.getPosition()]) == 0) {
        holder.mNumber.setText("");
        holder.mNumber.setVisibility(View.GONE);
        holder.mImgJian.setVisibility(View.GONE);
    } else {
        holder.mNumber.setText("" + mGoodsDataBaseInterface.getSecondGoodsNumber(mContext, MainActivity.SELECTPOSITION , DemoData.ListMenu_GOODSID[holder.getPosition()]));
        holder.mNumber.setVisibility(View.VISIBLE);
        holder.mImgJian.setVisibility(View.VISIBLE);
    }
    setOnListtener(holder);
}

b.自定义item点击、长点击、添加商品和减少商品的监听事件;

//触发
protected void setOnListtener(final ViewHolder holder){
   if(mOnItemClickListener != null){
       holder.itemView.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               mOnItemClickListener.onItemClick(holder);
           }
       });
       holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
           @Override
           public boolean onLongClick(View v) {
               mOnItemClickListener.onItemLongClick(holder);
               return true;
           }
       });
       holder.mImgJia.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               mOnItemClickListener.onItemJiaClick(holder);
           }
       });
       holder.mImgJian.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               mOnItemClickListener.onItemJianClick(holder);
           }
       });
   }
}

c.点击加号和减号的时候,进行相关的操作;

MainActivity.java

mRecyclerViewContentCommonadapter.setOnItemClickListener(new RecyclerViewContentAdapter.OnItemClickListener() {
@Override
public void onItemClick(RecyclerViewContentAdapter.ViewHolder holder) {}
@Override
public void onItemLongClick(RecyclerViewContentAdapter.ViewHolder holder) {}
/** 添加 */
@Override
public void onItemJiaClick(RecyclerViewContentAdapter.ViewHolder holder) {
    String numText = holder.mNumber.getText().toString().trim();
    /** 点击加号之前还没有数据的时候 */
    if (numText.isEmpty() || numText.equals("0")) {
        Log.e("TAG", "点击获取信息:SELECTPOSITION--" + SELECTPOSITION + "  DemoData.ListMenu_GOODSID[position]--" + DemoData.ListMenu_GOODSID[holder.getPosition()]);
        holder.mImgJian.setVisibility(View.VISIBLE);
        holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], "1", DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
        holder.mNumber.setVisibility(View.VISIBLE);
    }/** 点击加号之前有数据的时候 */
    else {
        holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], String.valueOf(Integer.parseInt(numText) + 1), DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
    }
    /** 动画 */
    GoodsAnimUtil.setAnim(MainActivity.this, holder.mImgJia, mCarLay);
    GoodsAnimUtil.setOnEndAnimListener(new onEndAnim());
    /** 统计购物总数和购物总价 */
}
/** 减少 */
@Override
public void onItemJianClick(RecyclerViewContentAdapter.ViewHolder holder) {
    String numText = holder.mNumber.getText().toString().trim();
    holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], String.valueOf(Integer.parseInt(numText) - 1), DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
    numText = holder.mNumber.getText().toString().trim();
    /** 减完之后  数据为0 */
    if (numText.equals("0")) {
        holder.mNumber.setVisibility(View.GONE);
        holder.mImgJian.setVisibility(View.GONE);
    }
    setAll();
}
});

d.在点击item的点击事件、点击加号监听动画结束和点击减号的时候都要调用setAll()方法进行商品总数和商品价格的数据更新;

/**
 * 点击加号和减号的时候设置总数和总价格
 */
private void setAll() {
 //设置所有购物数量
 if (mGoodsDataBaseInterface.getSecondGoodsNumberAll(mContext, SELECTPOSITION) == 0) {
     mListAllNum.setVisibility(View.GONE);
     mListAllPrice.setText("¥0");
     mListAllNum.setText("0");
 } else {
     mListAllPrice.setText("¥" + mGoodsDataBaseInterface.getSecondGoodsPriceAll(mContext, SELECTPOSITION) + "");
     mListAllNum.setText(mGoodsDataBaseInterface.getSecondGoodsNumberAll(mContext, SELECTPOSITION) + "");
     mListAllNum.setVisibility(View.VISIBLE);
 }
}

全部主代码 MainActivity.java

public class MainActivity extends BaseActivity {
    /**
     * 标题
     */
    @InjectView(R.id.m_fml_title_tv)
    TextView mTitle;
    /**
     * 侧边栏菜单RecyclerView
     */
    @InjectView(R.id.m_list_menu)
    RecyclerView mRecyclerMenu;
    /**
     * 内容RecyclerView
     */
    @InjectView(R.id.m_list_content)
    RecyclerView mRecyclerContent;
    /**
     * 商品总价
     */
    @InjectView(R.id.m_list_all_price)
    TextView mListAllPrice;
    /**
     * 物品总数量
     */
    @InjectView(R.id.m_list_num)
    TextView mListAllNum;
    /**
     * 侧边栏菜单数据填充器
     */
    private RecyclerViewMenuAdapter mRecyclerViewMenuCommonadapter = null;
    /**
     * 内容数据填充器
     */
    private RecyclerViewContentAdapter mRecyclerViewContentCommonadapter = null;
    private Context mContext;
    /**
     * 存储数据list
     */
    private List<String> stringMenuList = new ArrayList<String>();
    private List<String> stringContentList = new ArrayList<String>();
    public static int SELECTPOSITION = 0;
    /**
     * 数据操作接口
     */
    GoodsDataBaseInterface mGoodsDataBaseInterface = null;
    /**
     * 购物车布局
     */
    @InjectView(R.id.m_list_car_lay)
    RelativeLayout mCarLay;

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(MainActivity.this);
        mContext = this;
        initView();
        setRecyclerView();
        initHttp();
    }
    private void initView() {
        mGoodsDataBaseInterface = OperateGoodsDataBase.getInstance();
        //清空数据库缓存
        mGoodsDataBaseInterface.deleteAll(mContext);
        mTitle.setText("列表菜单");
    }
    /**
     * 模拟网络请求数据
     */
    private void initHttp() {
        for (int i = 0; i < 10; i++) {
            stringMenuList.add("1111");
        }
        for (int i = 0; i < 4; i++) {
            stringContentList.add("2222");
        }
        setMenuCommonadapter();
        setContentCommonadapter();
    }
    @OnClick({R.id.m_fml_title_back, R.id.m_list_submit})
    void onClick(View v) {
        switch (v.getId()) {
            case R.id.m_fml_title_back:
                finish();
                break;
            case R.id.m_list_submit:
                Toast.makeText(mContext, "提交", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
    }
    /**
     * 设置RecyclerView的布局方式
     */
    private void setRecyclerView() {
        //垂直listview显示方式
        mRecyclerMenu.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
        mRecyclerMenu.addItemDecoration(new DividerItemDecoration(mContext, LinearLayoutManager.VERTICAL));
        mRecyclerContent.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
    }
    /**
     * 菜单列表    数据填充
     */
    private void setMenuCommonadapter() {
        mRecyclerViewMenuCommonadapter = new RecyclerViewMenuAdapter(mContext, stringMenuList);
        mRecyclerMenu.setAdapter(mRecyclerViewMenuCommonadapter);
        mRecyclerViewMenuCommonadapter.setOnItemClickListener(new RecyclerViewMenuAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                SELECTPOSITION = position;
                Log.e("TAG", "SELECTPOSITION:" + SELECTPOSITION);
                mRecyclerViewMenuCommonadapter.notifyDataSetChanged();
                mRecyclerViewContentCommonadapter.notifyDataSetChanged();
                setAll();
            }
            @Override
            public void onItemLongClick(View v, int position) {}
        });
    }
    /**
     * 商品种类列表    数据填充
     */
    private void setContentCommonadapter() {
        mRecyclerViewContentCommonadapter = new RecyclerViewContentAdapter(mContext, stringContentList);
        mRecyclerContent.setAdapter(mRecyclerViewContentCommonadapter);
        mRecyclerViewContentCommonadapter.setOnItemClickListener(new RecyclerViewContentAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(RecyclerViewContentAdapter.ViewHolder holder) {}
            @Override
            public void onItemLongClick(RecyclerViewContentAdapter.ViewHolder holder) {}
            /** 添加 */
            @Override
            public void onItemJiaClick(RecyclerViewContentAdapter.ViewHolder holder) {
                String numText = holder.mNumber.getText().toString().trim();
                /** 点击加号之前还没有数据的时候 */
                if (numText.isEmpty() || numText.equals("0")) {
                    Log.e("TAG", "点击获取信息:SELECTPOSITION--" + SELECTPOSITION + "  DemoData.ListMenu_GOODSID[position]--" + DemoData.ListMenu_GOODSID[holder.getPosition()]);
                    holder.mImgJian.setVisibility(View.VISIBLE);
                    holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], "1", DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
                    holder.mNumber.setVisibility(View.VISIBLE);
                }/** 点击加号之前有数据的时候 */
                else {
                    holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], String.valueOf(Integer.parseInt(numText) + 1), DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
                }
                /** 动画 */
                GoodsAnimUtil.setAnim(MainActivity.this, holder.mImgJia, mCarLay);
                GoodsAnimUtil.setOnEndAnimListener(new onEndAnim());
                /** 统计购物总数和购物总价 */
            }
            /** 减少 */
            @Override
            public void onItemJianClick(RecyclerViewContentAdapter.ViewHolder holder) {
                String numText = holder.mNumber.getText().toString().trim();
                holder.mNumber.setText(mGoodsDataBaseInterface.saveGoodsNumber(mContext, SELECTPOSITION, DemoData.ListMenu_GOODSID[holder.getPosition()], String.valueOf(Integer.parseInt(numText) - 1), DemoData.ListMenu_PPRICE[holder.getPosition()]) + "");
                numText = holder.mNumber.getText().toString().trim();
                /** 减完之后  数据为0 */
                if (numText.equals("0")) {
                    holder.mNumber.setVisibility(View.GONE);
                    holder.mImgJian.setVisibility(View.GONE);
                }
                setAll();
            }
        });
    }
    /**
     * 动画结束后,更新所有数量和所有价格
     */
    class onEndAnim implements GoodsAnimUtil.OnEndAnimListener {
        @Override
        public void onEndAnim() {
            setAll();
        }
    }
    /**
     * 点击加号和减号的时候设置总数和总价格
     */
    private void setAll() {
        //设置所有购物数量
        if (mGoodsDataBaseInterface.getSecondGoodsNumberAll(mContext, SELECTPOSITION) == 0) {
            mListAllNum.setVisibility(View.GONE);
            mListAllPrice.setText("¥0");
            mListAllNum.setText("0");
        } else {
            mListAllPrice.setText("¥" + mGoodsDataBaseInterface.getSecondGoodsPriceAll(mContext, SELECTPOSITION) + "");
            mListAllNum.setText(mGoodsDataBaseInterface.getSecondGoodsNumberAll(mContext, SELECTPOSITION) + "");
            mListAllNum.setVisibility(View.VISIBLE);
        }
    }
}

由于牵扯到3个知识点,所以逻辑可能有些乱,所以大家可以查看我编写的代码,里面注释十分详细,有意见或者疑问的可以共同商讨。

源码下载地址

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
实现数据添加到购物车效果,需要前端和后端的配合。 前端部分: 1. 在 HTML 页面中添加购物车按钮,并为其绑定一个事件监听器; 2. 在事件监听器中使用 AJAX 技术向后端发送请求,请求添加商品到购物车中; 3. 显示添加成功或失败的信息。 一个简单的HTML页面代码示例: ```html <!DOCTYPE html> <html> <head> <title>商品列表</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $(document).ready(function() { $(".add-to-cart").click(function() { var id = $(this).data("id"); $.ajax({ url: "addToCart.php", method: "POST", data: {id: id}, success: function(response) { $(".message").html(response); } }); }); }); </script> </head> <body> <h1>商品列表</h1> <ul> <li>商品1 <button class="add-to-cart" data-id="1">加入购物车</button></li> <li>商品2 <button class="add-to-cart" data-id="2">加入购物车</button></li> <li>商品3 <button class="add-to-cart" data-id="3">加入购物车</button></li> </ul> <div class="message"></div> </body> </html> ``` 在这个示例中,我们为每个商品添加了一个加入购物车的按钮,并为每个按钮设置了一个 `data-id` 属性,用来表示该商品的唯一标识符。当用户点击加入购物车按钮时,我们使用 AJAX 技术向后端发送请求,并将商品的唯一标识符作为参数传递给后端。 后端部分: 1. 接收前端发送的请求,获取商品的唯一标识符; 2. 根据商品的唯一标识符从数据库中获取商品的信息; 3. 将商品的信息添加到购物车中,并将购物车保存到 session 中; 4. 返回添加成功或失败的信息给前端。 一个简单的PHP代码示例: ```php <?php session_start(); if ($_SERVER["REQUEST_METHOD"] == "POST") { $id = $_POST["id"]; // 根据商品的唯一标识符从数据库中获取商品信息 $item = getItemById($id); if ($item) { // 将商品信息添加到购物车中 if (!isset($_SESSION["cart"])) { $_SESSION["cart"] = array(); } array_push($_SESSION["cart"], $item); echo "商品已添加到购物车。"; } else { echo "商品不存在。"; } } ?> ``` 在这个示例中,我们首先获取前端发送的请求中的商品唯一标识符,并根据该标识符从数据库中获取商品信息。如果商品存在,我们将其添加到购物车中,并将购物车保存到 session 中。最后,我们返回添加成功或失败的信息给前端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值