MVP实现二级购物车
来源:互联网 发布:云计算 大会 编辑:程序博客网 时间:2024/05/21 22:32
效果图
使用接口:http://120.27.23.105/product/getCarts?uid=100
导入依赖
compile 'com.squareup.okhttp3:okhttp:3.9.0' compile 'com.google.code.gson:gson:2.8.2' compile 'com.android.support:recyclerview-v7:25.3.1' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'清单文件中加入权限
<uses-permission android:name="android.permission.INTERNET"/>配置application的name属性,ImageLoader初始化
<application android:name=".appli.App"</application>
public class App extends Application{ @Override public void onCreate() { super.onCreate(); ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this).build(); ImageLoader.getInstance().init(configuration); }}
布局中需要用到的的布局,在drawable下面新建qujiesuan.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="200dp"/> <solid android:color="#e53e42"/> <size android:height="60dp" android:width="130dp"/></shape>drawable下面还需要加入三张图片
接下来就是activity_main.xml里面的布局,上面是recyclerView下面是一系列的功能
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v7.widget.RecyclerView android:id="@+id/recycler_View" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <LinearLayout android:gravity="center_vertical" android:padding="10dp" android:orientation="horizontal" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content"> <CheckBox android:background="@drawable/shopcart_unselected" android:button="@null" android:id="@+id/quanxuan" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:textStyle="bold" android:layout_marginLeft="10dp" android:textSize="23sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="全选" /> <LinearLayout android:padding="10dp" android:layout_marginLeft="10dp" android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content"> <TextView android:textColor="#e53e42" android:id="@+id/total_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="总价 : ¥0元" /> <TextView android:id="@+id/total_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="共0件商品" /> </LinearLayout> <TextView android:gravity="center" android:textSize="25sp" android:text="去结算" android:textColor="#fff" android:background="@drawable/qujiesuan" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout></LinearLayout>
自定义组合控件,,
custom_jiajian.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="horizontal" android:gravity="center_vertical" android:layout_height="wrap_content"> <Button android:background="#fff" android:textSize="20sp" android:id="@+id/reverse" android:text="一" android:layout_width="50dp" android:layout_height="wrap_content" /> <EditText android:textStyle="bold" android:textSize="23sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1" android:id="@+id/count" /> <Button android:id="@+id/add" android:background="#fff" android:textSize="25sp" android:text="+" android:layout_width="50dp" android:layout_height="wrap_content" /></LinearLayout>
适配器的条目的布局,recy_cart_item.xml
com.example.day20_mvp_cart.customView.CustomJiaJian 别忘了改成自己的包名下的,否则会报错
recy_cart_item.xml,需要引入 自定义组合控件,在创建了CustomJiaJian类以后才可以引入
recy_cart_item.xml适配器的布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="vertical" android:padding="15dp" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <CheckBox android:id="@+id/shop_checkbox" android:layout_width="50dp" android:layout_height="50dp" /> <TextView android:layout_marginLeft="20dp" android:text="良品铺子" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="23sp" android:textStyle="bold" android:id="@+id/shop_name" /> </LinearLayout> <LinearLayout android:gravity="center_vertical" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <CheckBox android:id="@+id/item_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/item_face" android:src="@mipmap/ic_launcher" android:layout_width="120dp" android:layout_height="120dp" /> <LinearLayout android:layout_marginLeft="10dp" android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content"> <TextView android:id="@+id/item_name" android:textSize="20sp" android:text="三只松鼠" android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="0dp" /> <TextView android:textColor="#f00" android:id="@+id/item_price" android:textSize="23sp" android:text="299" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" /> <com.example.day171122_cart.customview.CustomJiaJian android:id="@+id/custom_jiajian" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout> <ImageView android:id="@+id/item_delete" android:layout_marginRight="10dp" android:src="@drawable/shopcart_delete" android:layout_width="30dp" android:layout_height="30dp" /> </LinearLayout></LinearLayout>
接着写代码里面的,首先将自定义组合控件的类填充在视图里
自定义组合控件的类,CustomJiaJian.java继承LinearLayout,inflate填充布局,+和-的点击事件回调给adapter
CustomJiaJian.java
public class CustomJiaJian extends LinearLayout{ private Button reverse; private Button add; private EditText countEdit; private int mCount =1; public CustomJiaJian(Context context) { super(context); } public CustomJiaJian(Context context, AttributeSet attrs) { super(context, attrs); View view = View.inflate(context, R.layout.custom_jiajian,this); reverse = (Button) view.findViewById(R.id.reverse); add = (Button) view.findViewById(R.id.add); countEdit = (EditText) view.findViewById(R.id.count); reverse.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String content = countEdit.getText().toString().trim(); int count = Integer.valueOf(content); if(count>1){ mCount = count-1; countEdit.setText(mCount+""); //回调给adapter里面 if(customListener!=null){ customListener.jiajian(mCount); } } } }); add.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String content = countEdit.getText().toString().trim(); int count = Integer.valueOf(content)+1; mCount = count; countEdit.setText(mCount+""); //接口回调给adapter if(customListener!=null){ customListener.jiajian(mCount); } } }); } public CustomJiaJian(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } CustomListener customListener; public void setCustomListener(CustomListener customListener){ this.customListener = customListener; } //加减的接口 public interface CustomListener{ public void jiajian(int count); public void shuRuZhi(int count); } //这个方法是供recyadapter设置 数量时候调用的 public void setEditText(int num) { if(countEdit !=null) { countEdit.setText(num + ""); } }}
下面就是okhttp二次封装的类,这里就不详细叙述了,详见okhttp封装类,拦截器地址
根据最上面给出的接口.访问到的数据,生成一个实体类CartBean
在CartBean类里面自己添加三个字段,isFirst,item_check,shop_check
//自己添加的三个字段 private int isFirst = 1;//1为显示商铺, 2为隐藏商铺 private boolean item_check;//每个商品的选中状态 private boolean shop_check;//商店的选中状态 public int getIsFirst() { return isFirst; } public void setIsFirst(int isFirst) { this.isFirst = isFirst; } public boolean isItem_check() { return item_check; } public void setItem_check(boolean item_check) { this.item_check = item_check; } public boolean isShop_check() { return shop_check; } public void setShop_check(boolean shop_check) { this.shop_check = shop_check; }
接下来就是使用MVP架构模式..首先创建presenter和model层,View这里默认就是MainActivity
写两个接口,一个是ModelCallBack是model层的回调接口,ViewCallBack是view层的回调接口
ModelCallBack.java
public interface ModelCallBack { public void success(CartBean cartBean); public void failure(Exception e);}
ViewCallBack.java
public interface ViewCallBack { public void success(CartBean cartBean); public void failure(Exception e);}
下面是重要的MainActivity.java, 调用presenter层的方法,实现view层的接口的方法,还调用适配器adapter里面的接口
public class MainActivity extends AppCompatActivity implements ViewCallBack{ private RecyclerView recyclerView; private TextView total_price; private TextView total_num; private CheckBox quanxuan; private MyPresenter myPresenter; private RecyAdapter recyAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //http://120.27.23.105/product/getCarts?uid=100 recyclerView = (RecyclerView) findViewById(R.id.recycler_View); total_price = (TextView) findViewById(R.id.total_price); total_num = (TextView) findViewById(R.id.total_num); quanxuan = (CheckBox) findViewById(R.id.quanxuan); quanxuan.setTag(1);//1为不选中 LinearLayoutManager manager = new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,false); //new出适配器 recyAdapter = new RecyAdapter(this); myPresenter = new MyPresenter(this); //调用presenter里面的请求数据的方法 myPresenter.getData(); recyclerView.setLayoutManager(manager); recyclerView.setAdapter(recyAdapter); //调用recyAdapter里面的接口,设置 全选按钮 总价 总数量 recyAdapter.setUpdateListener(new RecyAdapter.UpdateListener() { @Override public void setTotal(String total, String num, boolean allCheck) { //设置ui的改变 total_num.setText("共"+num+"件商品");//总数量 total_price.setText("总价 :¥"+total+"元");//总价 if(allCheck){ quanxuan.setTag(2); quanxuan.setBackgroundResource(R.drawable.shopcart_selected); }else{ quanxuan.setTag(1); quanxuan.setBackgroundResource(R.drawable.shopcart_unselected); } quanxuan.setChecked(allCheck); } }); //这里只做ui更改, 点击全选按钮,,调到adapter里面操作 quanxuan.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //调用adapter里面的方法 ,,把当前quanxuan状态传递过去 int tag = (int) quanxuan.getTag(); if(tag==1){ quanxuan.setTag(2); quanxuan.setBackgroundResource(R.drawable.shopcart_selected); }else{ quanxuan.setTag(1); quanxuan.setBackgroundResource(R.drawable.shopcart_unselected); } recyAdapter.quanXuan(quanxuan.isChecked()); } }); } //实现接口,重写的方法 @Override public void success(CartBean cartBean) { //拿到返回来的数据 ,, 传给适配器数据 recyAdapter.add(cartBean); } @Override public void failure(final Exception e) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this,"error",Toast.LENGTH_SHORT).show(); } }); } @Override protected void onDestroy() { super.onDestroy(); //调用p层的解除绑定 myPresenter.detach(); }}
MyPresenter.java,presenter层里面 调用model层的方法,,防止内存泄露解绑
public class MyPresenter { MyModel myModel = new MyModel(); ViewCallBack viewCallBack; public MyPresenter(ViewCallBack viewCallBack) { this.viewCallBack = viewCallBack; } //调用model 层的请求数据 public void getData(){ myModel.getData(new ModelCallBack() { @Override public void success(CartBean cartBean) { if(viewCallBack!=null) { viewCallBack.success(cartBean); } } @Override public void failure(Exception e) { if(viewCallBack!=null) { viewCallBack.failure(e); } } }); } /** * 防止内存泄露 * */ public void detach(){ viewCallBack=null; }}
MyModel.java,model层里面 调用okhttp的封装类 单例模式,请求网络数据.返回一个bean类,类型改成CartBean
上面已经放过了MainActivity接收到model传给presenter.presenter传给view 的CartBean以后,将数据添加给适配器,
public class MyModel { public void getData(final ModelCallBack modelCallBack){ //访问接口 String path = "http://120.27.23.105/product/getCarts?uid=100"; OkhttpUtils.getInstance().asy(null, path, new AbstractUiCallBack<CartBean>() { @Override public void success(CartBean cartBean) { modelCallBack.success(cartBean); } @Override public void fail(Exception e) { modelCallBack.failure(e); } }); }}
下面是适配器RecyAdapter.java 这里面的操作量就很大,包括了对每个条目的一系列操作,删除,选中,和对自定义视图加减号改变数量等,和是否显示和隐藏一级商家的信息,求总价,总数量等,部分操作也用到了接口回调出去
public class RecyAdapter extends RecyclerView.Adapter<RecyAdapter.MyViewHolder>{ Context context; //创建大的集合 private List<CartBean.DataBean.ListBean> list; //存放商家的id和商家的名称的map集合 private Map<String,String> map = new HashMap<>(); public RecyAdapter(Context context) { this.context = context; } /** * 添加数据并更新显示 * */ public void add(CartBean cartBean){ //传进来的是bean对象 if(list == null){ list = new ArrayList<>(); } //第一层遍历商家和商品 for (CartBean.DataBean shop : cartBean.getData()){ //把商品的id和商品的名称添加到map集合里 ,,为了之后方便调用 map.put(shop.getSellerid(),shop.getSellerName()); //第二层遍历里面的商品 for (int i=0;i<shop.getList().size();i++){ //添加到list集合里 list.add(shop.getList().get(i)); } } //调用方法 设置显示或隐藏 商铺名 setFirst(list); notifyDataSetChanged(); } /** * 设置数据源,控制是否显示商家 * */ private void setFirst(List<CartBean.DataBean.ListBean> list) { if(list.size()>0){ //如果是第一条数据就设置isFirst为1 list.get(0).setIsFirst(1); //从第二条开始遍历 for (int i=1;i<list.size();i++){ //如果和前一个商品是同一家商店的 if (list.get(i).getSellerid() == list.get(i-1).getSellerid()){ //设置成2不显示商铺 list.get(i).setIsFirst(2); }else{//设置成1显示商铺 list.get(i).setIsFirst(1); //如果当前条目选中,把当前的商铺也选中 if (list.get(i).isItem_check()==true){ list.get(i).setShop_check(list.get(i).isItem_check()); } } } } } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(context, R.layout.recy_cart_item,null); MyViewHolder myViewHolder = new MyViewHolder(view); return myViewHolder; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { /** * 设置商铺的 shop_checkbox和商铺的名字 显示或隐藏 * */ if(list.get(position).getIsFirst()==1){ //显示商家 holder.shop_checkbox.setVisibility(View.VISIBLE); holder.shop_name.setVisibility(View.VISIBLE); //设置shop_checkbox的选中状态 holder.shop_checkbox.setChecked(list.get(position).isShop_check()); holder.shop_name.setText(map.get(String.valueOf(list.get(position).getSellerid()))); }else{//2 //隐藏商家 holder.shop_name.setVisibility(View.GONE); holder.shop_checkbox.setVisibility(View.GONE); } //拆分images字段 String[] split = list.get(position).getImages().split("\\|"); //设置商品的图片 ImageLoader.getInstance().displayImage(split[0],holder.item_face); //控制商品的item_checkbox,,根据字段改变 holder.item_checkbox.setChecked(list.get(position).isItem_check()); holder.item_name.setText(list.get(position).getTitle()); holder.item_price.setText(list.get(position).getPrice()+""); //调用customjiajian里面的方法设置 加减号中间的数字 holder.customJiaJian.setEditText(list.get(position).getNum()); //商铺的shop_checkbox点击事件 ,控制商品的item_checkbox holder.shop_checkbox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //先改变数据源中的shop_check list.get(position).setShop_check(holder.shop_checkbox.isChecked()); for (int i=0;i<list.size();i++){ //如果是同一家商铺的 都给成相同状态 if(list.get(position).getSellerid()==list.get(i).getSellerid()){ //当前条目的选中状态 设置成 当前商铺的选中状态 list.get(i).setItem_check(holder.shop_checkbox.isChecked()); } } //刷新适配器 notifyDataSetChanged(); //调用求和的方法 sum(list); } }); //商品的item_checkbox点击事件,控制商铺的shop_checkbox holder.item_checkbox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //先改变数据源中的item_checkbox list.get(position).setItem_check(holder.item_checkbox.isChecked()); //反向控制商铺的shop_checkbox for (int i=0;i<list.size();i++){ for (int j=0;j<list.size();j++){ //如果两个商品是同一家店铺的 并且 这两个商品的item_checkbox选中状态不一样 if(list.get(i).getSellerid()==list.get(j).getSellerid() && !list.get(j).isItem_check()){ //就把商铺的shop_checkbox改成false list.get(i).setShop_check(false); break; }else{ //同一家商铺的商品 选中状态都一样,就把商铺shop_checkbox状态改成true list.get(i).setShop_check(true); } } } //更新适配器 notifyDataSetChanged(); //调用求和的方法 sum(list); } }); //删除条目的点击事件 holder.item_delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { list.remove(position);//移除集合中的当前数据 //删除完当前的条目 重新判断商铺的显示隐藏 setFirst(list); //调用重新求和 sum(list); notifyDataSetChanged(); } }); //加减号的监听, holder.customJiaJian.setCustomListener(new CustomJiaJian.CustomListener() { @Override public void jiajian(int count) { //改变数据源中的数量 list.get(position).setNum(count); notifyDataSetChanged(); sum(list); } @Override //输入值 求总价 public void shuRuZhi(int count) { list.get(position).setNum(count); notifyDataSetChanged(); sum(list); } }); } /** * 计算总价的方法 * */ private void sum(List<CartBean.DataBean.ListBean> list){ int totalNum = 0;//初始的总价为0 float totalMoney = 0.0f; boolean allCheck = true; for (int i=0;i<list.size();i++){ //把 已经选中的 条目 计算价格 if (list.get(i).isItem_check()){ totalNum += list.get(i).getNum(); totalMoney += list.get(i).getNum() * list.get(i).getPrice(); }else{ //如果有个未选中,就标记为false allCheck = false; } } //接口回调出去 把总价 总数量 和allcheck 传给view层 updateListener.setTotal(totalMoney+"",totalNum+"",allCheck); } //view层调用这个方法, 点击quanxuan按钮的操作 public void quanXuan(boolean checked) { for (int i=0;i<list.size();i++){ list.get(i).setShop_check(checked); list.get(i).setItem_check(checked); } notifyDataSetChanged(); sum(list); } @Override public int getItemCount() { return list==null?0:list.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { private final CheckBox shop_checkbox; private final TextView shop_name; private final CheckBox item_checkbox; private final TextView item_name; private final TextView item_price; private final CustomJiaJian customJiaJian; private final ImageView item_delete; private final ImageView item_face; public MyViewHolder(View itemView) { super(itemView); shop_checkbox = (CheckBox) itemView.findViewById(R.id.shop_checkbox); shop_name = (TextView) itemView.findViewById(R.id.shop_name); item_checkbox = (CheckBox) itemView.findViewById(R.id.item_checkbox); item_name = (TextView) itemView.findViewById(R.id.item_name); item_price = (TextView) itemView.findViewById(R.id.item_price); customJiaJian = (CustomJiaJian) itemView.findViewById(R.id.custom_jiajian); item_delete = (ImageView) itemView.findViewById(R.id.item_delete); item_face = (ImageView) itemView.findViewById(R.id.item_face); } } UpdateListener updateListener; public void setUpdateListener(UpdateListener updateListener){ this.updateListener = updateListener; } //接口 public interface UpdateListener{ public void setTotal(String total,String num,boolean allCheck); }}
- MVP实现二级购物车
- MVP实现二级购物车
- mvp二级购物车的实现
- MVP+Retrofit实现二级购物车
- 二级购物车+MVP
- MVP二级购物车
- MVP二级购物车
- MVP二级购物车
- MVP做二级购物车
- MVP模式二级购物车
- 购物车+MVP+二级列表
- Android用MVP实现的二级列表购物车
- Android二级购物车MVP实现(布局篇)
- Android实现带商家的二级购物车+MVP
- android购物车二级列表实现+MVP+Okhttp
- 二级列表展示购物车MVP
- 购物车二级列表MVP封装
- MVP模式下的二级购物车
- 漫谈Hadoop的思想之源:Google
- 存储过程调试
- 谈谈数据库的ACID
- 构造函数,析构函数与virtual
- [转载整理]计算机视觉及机器学习牛人和资料
- MVP实现二级购物车
- java 公用的解析json的方式,将json转换成集合的模式存放
- ejabberd源码分析《一》application启动
- iOS 自定义tabbar中间按钮 超简单方法
- OPP :面向对象编程,深入理解类class
- java.lang.RuntimeException: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMerger
- Greendao+多线程断点续传
- 数据结构实验之图论九:最小生成树
- svn分支与合并