效果图
使用接口: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
- 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>
接下来就是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>
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);
- }
- }