您的位置:首页 > 其它

MVP实现二级购物车

2017-12-27 09:08 344 查看
效果图
使用接口:http://120.27.23.105/product/getCarts?uid=100






导入依赖

[html] view
plain copy

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'

清单文件中加入权限

[html] view
plain copy

<uses-permission android:name="android.permission.INTERNET"/>

配置application的name属性,ImageLoader初始化

[html] view
plain copy

<application

android:name=".appli.App"

</application>

[html] view
plain copy

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

[html] view
plain copy

<?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



[html] view
plain copy

<?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

[html] view
plain copy

<?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适配器的布局

[html] view
plain copy

<?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

[html] view
plain copy

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

[html] view
plain copy

//自己添加的三个字段

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

[html] view
plain copy

public interface ModelCallBack {

public void success(CartBean cartBean);

public void failure(Exception e);

}

ViewCallBack.java

[html] view
plain copy

public interface ViewCallBack {

public void success(CartBean cartBean);

public void failure(Exception e);

}

下面是重要的MainActivity.java, 调用presenter层的方法,实现view层的接口的方法,还调用适配器adapter里面的接口

[html] view
plain copy

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层的方法,,防止内存泄露解绑

[html] view
plain copy

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以后,将数据添加给适配器,

[html] view
plain copy

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 这里面的操作量就很大,包括了对每个条目的一系列操作,删除,选中,和对自定义视图加减号改变数量等,和是否显示和隐藏一级商家的信息,求总价,总数量等,部分操作也用到了接口回调出去

[html] view
plain copy

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);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: