效果图:
加依赖:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.google.code.gson:gson:2.8.2' implementation 'com.squareup.okhttp3:okhttp:3.9.0' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'org.greenrobot:eventbus:3.1.1' implementation 'com.squareup.retrofit2:converter-gson:2.0.2' implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0' implementation 'io.reactivex.rxjava2:rxjava:2.0.2' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' implementation 'com.squareup.retrofit2:retrofit:2.0.2' }
RetrofitApi:
/** * author:Created by WeiWeiFeng on 2018/5/16. */ public interface RetrofitApi { //https://www.zhaoapi.cn/product/getCarts?uid=13850&source=android" @GET("product/getCarts?uid=13850&source=android") Observable<Goods> getShoppingData(); }
RetrofitUtils:
public class RetrofitUtils { public static RetrofitApi retrofitApi; static { HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLogger()); logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient().newBuilder() .addNetworkInterceptor(logInterceptor) //.addInterceptor(new LoggingInterceptor()) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(API.BASE_URL) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build(); retrofitApi = retrofit.create(RetrofitApi.class); } private static class HttpLogger implements HttpLoggingInterceptor.Logger { @Override public void log(String message) { Log.e("TAG", message ); } } }
BasePresenter:
public class BasePresenter<V extends IBaseView> { private V mIBaseView; public void attachView(V iBaseView) { this.mIBaseView = iBaseView; } public void detachView() { mIBaseView = null; } public V getView() { return mIBaseView; } }
MainPresenter:
public class MainPresenter extends BasePresenter<IMainView> { private final HttpUtils httpUtils; public MainPresenter() { httpUtils = HttpUtils.getHttpUtils(); } @SuppressLint("CheckResult") public void getData() { Observable<Goods> observable = RetrofitUtils.retrofitApi.getShoppingData(); observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Goods>() { @Override public void accept(Goods goods) throws Exception { List<Goods.DataBean> data = goods.getData(); getView().onScuess(data); } }); } }
BaseActivity:
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements IBaseView{ public P presenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(setChildView()); initView(); initBaseView(); initData(); } private void initBaseView() { presenter = getPresenter(); if (presenter != null) { presenter.attachView(this); } else { try { throw new Exception("出错了"); } catch (Exception e) { e.printStackTrace(); } } } protected abstract P getPresenter(); protected abstract void initView(); protected abstract int setChildView(); protected abstract void initData(); }
重点实现购物车
MainActivity:
public class MainActivity extends BaseActivity<MainPresenter> implements IMainView { private static final String TAG = "MainActivity"; private ExpandableListView mElv; CheckBox cbSelectAll; private TextView tvAllMoney; private TextView tvTransport; private Button btnSettlement; String url = "https://www.zhaoapi.cn/product/getCarts?uid=13850&source=android"; private MyAdapter adapter; private List<Goods.DataBean> data; @SuppressLint("HandlerLeak") private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 1) { data = (List<Goods.DataBean>) msg.obj; adapter = new MyAdapter(MainActivity.this, data); mElv.setAdapter(adapter); mElv.setGroupIndicator(null); //默认让其全部展开 for (int i = 0; i < data.size(); i++) { mElv.expandGroup(i); } adapter.notifyDataSetChanged(); } } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //注册EventBus EventBus.getDefault().register(this); } @Override protected void initData() { presenter.getData(url); } @Override protected MainPresenter getPresenter() { return new MainPresenter(); } @Override protected void initView() { mElv = (ExpandableListView) findViewById(R.id.expandableListView); cbSelectAll = (CheckBox) findViewById(R.id.cb_select_all); tvAllMoney = (TextView) findViewById(R.id.tv_all_money); tvTransport = (TextView) findViewById(R.id.tv_transport); btnSettlement = (Button) findViewById(R.id.btn_settlement); btnSettlement.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, RescudActivity.class); startActivity(intent); } }); //点击全选按钮 cbSelectAll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { adapter.changeAllListCbState(cbSelectAll.isChecked()); } }); } @Override protected int setChildView() { return R.layout.activity_main; } @Override public void onScuess(List<Goods.DataBean> data) { // Log.e("TAG", "onScuess: "+data.size()); Message message = handler.obtainMessage(); message.what = 1; message.obj = data; handler.sendMessage(message); } /** * 获取传过来的全选状态值 * * @param msg */ @Subscribe(threadMode = ThreadMode.MAIN) public void getCheckBox(EventMessage msg) { boolean name = msg.isChecked(); cbSelectAll.setChecked(name); Log.e(TAG, "getMess: " + name); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PriceAndCountEvent event) { tvAllMoney.setText(event.getPrice() + ""); btnSettlement.setText("结算(" + event.getCount() + ")"); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
Adapter
public class MyAdapter extends BaseExpandableListAdapter { private Context context; private List<Goods.DataBean> data; public MyAdapter(Context context, List<Goods.DataBean> data) { this.context = context; this.data = data; } @Override public int getGroupCount() { return data.size(); } @Override public int getChildrenCount(int i) { return data.get(i).getList().size(); } @Override public Object getGroup(int i) { return data.get(i); } @Override public Object getChild(int i, int i1) { return data.get(i).getList().get(i1); } @Override public long getGroupId(int i) { return i; } @Override public long getChildId(int i, int i1) { return i1; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(final int i, boolean b, View view, ViewGroup viewGroup) { final ViewHolderGroup group; if (view == null) { view = View.inflate(context, R.layout.group_item, null); group = new ViewHolderGroup(); group.cb_parent = view.findViewById(R.id.cb_parent); group.tv_sign = view.findViewById(R.id.tv_sign); view.setTag(group); } else { group = (ViewHolderGroup) view.getTag(); } group.cb_parent.setChecked(data.get(i).isChecked()); group.tv_sign.setText(data.get(i).getSellerName()); //一级Checkbox group.cb_parent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { data.get(i).setChecked(group.cb_parent.isChecked()); changeChildCbState(i, group.cb_parent.isChecked()); EventBus.getDefault().post(compute()); changeAllCbState(isAllGroupCbSelected()); notifyDataSetChanged(); } }); return view; } @Override public View getChildView(final int i, final int i1, boolean b, View view, ViewGroup viewGroup) { final ViewHolderChild child; if (view == null) { view = View.inflate(context, R.layout.child, null); child = new ViewHolderChild(); child.cb_child = view.findViewById(R.id.cb_child); child.tv_content = view.findViewById(R.id.tv_content); child.tv_del = view.findViewById(R.id.tv_del); child.tv_num = view.findViewById(R.id.tv_num); child.tv_pri = view.findViewById(R.id.tv_pri); child.iv_add=view.findViewById(R.id.iv_add); child.iv_jian=view.findViewById(R.id.iv_jian); view.setTag(child); } else { child = (ViewHolderChild) view.getTag(); } child.cb_child.setChecked(data.get(i).getList().get(i1).isChildChecked()); child.tv_content.setText(data.get(i).getList().get(i1).getTitle()); child.tv_num.setText(data.get(i).getList().get(i1).getNum() + ""); child.tv_pri.setText(data.get(i).getList().get(i1).getPrice() + ""); //二级CheckBox child.cb_child.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //设置该条目对象里的Checked属性 data.get(i).getList().get(i1).setChildChecked(child.cb_child.isChecked()); EventBus.getDefault().post(compute()); if (child.cb_child.isChecked()) { if (isAllChildCbSelected(i)) { changGroupCbState(i, true); changeAllCbState(isAllGroupCbSelected()); } } else { changGroupCbState(i, false); changeAllCbState(isAllGroupCbSelected()); } //在此处刷新容易出现小bug 所以改到了changGroupCbState // notifyDataSetInvalidated(); } }); //加号 child.iv_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int num = data.get(i).getList().get(i1).getNum(); child.tv_num.setText(++num + ""); data.get(i).getList().get(i1).setNum(num); if (child.cb_child.isChecked()) { PriceAndCountEvent compute = compute(); EventBus.getDefault().post(compute); } } }); // 减号 child.iv_jian.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int num = data.get(i).getList().get(i1).getNum(); if (num == 0) { return; } child.tv_num.setText(--num + ""); data.get(i).getList().get(i1).setNum(num); if (child.cb_child.isChecked()) { PriceAndCountEvent compute = compute(); EventBus.getDefault().post(compute); } } }); //删除 child.tv_del.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { data.get(i).getList().remove(i1); if (data.get(i).getList().size()==0){ data.remove(i); } EventBus.getDefault().post(compute()); notifyDataSetInvalidated(); } }); return view; } @Override public boolean isChildSelectable(int i, int i1) { return true; } class ViewHolderGroup { private CheckBox cb_parent; private TextView tv_sign; } class ViewHolderChild { private CheckBox cb_child; private TextView tv_content, tv_pri, tv_num, tv_del; private ImageView iv_add, iv_jian; } /** * 改变全选按钮 * * @param fla */ private void changeAllCbState(boolean fla) { EventMessage eventMessage = new EventMessage(); eventMessage.setChecked(fla); EventBus.getDefault().post(eventMessage); } /** * 改变一级列表checkbox状态 * * @param groupPosition */ private void changGroupCbState(int groupPosition, boolean flag) { Goods.DataBean dataBean = data.get(groupPosition); dataBean.setChecked(flag); notifyDataSetChanged(); } /** * 点击一级列表的CheckBox * 改变二级列表CheckBox状态 * * @param i * @param flag */ private void changeChildCbState(int i, boolean flag) { List<Goods.DataBean.ListBean> list = data.get(i).getList(); for (int j = 0; j < list.size(); j++) { Goods.DataBean.ListBean listBean = list.get(j); listBean.setChildChecked(flag); } } /** * 判断所有的一级checkbox是否全选 * * @return */ private boolean isAllGroupCbSelected() { for (int i = 0; i < data.size(); i++) { Goods.DataBean dataBean = data.get(i); if (!dataBean.isChecked()) { return false; } } return true; } /** * 判断所有的二级checkbox是否全选 * * @param groupPosition * @return */ private boolean isAllChildCbSelected(int groupPosition) { List<Goods.DataBean.ListBean> list = data.get(groupPosition).getList(); for (int i = 0; i < list.size(); i++) { Goods.DataBean.ListBean listBean = list.get(i); if (!listBean.isChildChecked()) { return false; } } return true; } /** * 计算选中的价钱和数量 */ private PriceAndCountEvent compute() { int count = 0; int price = 0; for (int i = 0; i <data.size(); i++) { List<Goods.DataBean.ListBean> list = data.get(i).getList(); for (int j = 0; j < list.size(); j++) { Goods.DataBean.ListBean listBean = list.get(j); if (listBean.isChildChecked()){ count+=listBean.getNum(); price+=listBean.getNum()*listBean.getPrice(); } } } PriceAndCountEvent priceAndCountEvent = new PriceAndCountEvent(); priceAndCountEvent.setPrice(price); priceAndCountEvent.setCount(count); return priceAndCountEvent; } /** * 设置反选全选 * * @param flag */ public void changeAllListCbState(boolean flag) { for (int i = 0; i < data.size(); i++) { changGroupCbState(i, flag); changeChildCbState(i, flag); } EventBus.getDefault().post(compute()); notifyDataSetChanged(); } }
//布局文件
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".view.activity.MainActivity"> <ExpandableListView android:id="@+id/expandableListView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:scrollbars="none" android:divider="@null"/> <View android:layout_width="match_parent" android:layout_height="1dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="49dp" android:background="@android:color/white" android:gravity="center_vertical" android:orientation="horizontal"> <CheckBox android:id="@+id/cb_select_all" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginLeft="15dp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_weight="0.69" android:text="全选" android:textColor="#333333" android:textSize="15sp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="end" android:orientation="vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="合计" android:textColor="#333333" android:textSize="15sp" /> <TextView android:id="@+id/tv_all_money" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="¥0" android:textColor="#FE3824" android:textSize="15sp" /> </LinearLayout> <TextView android:id="@+id/tv_transport" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="运费:¥0" android:textColor="#999999" android:textSize="11sp" /> </LinearLayout> <Button android:id="@+id/btn_settlement" android:layout_width="95dp" android:layout_height="match_parent" android:layout_marginLeft="15dp" android:background="#FE3824" android:text="结算(0)" android:textColor="@android:color/white" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
group_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:layout_height="100dp" android:gravity="center_vertical" android:orientation="horizontal"> <CheckBox android:id="@+id/cb_parent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_marginLeft="20dp" android:layout_marginTop="30dp" android:focusable="false" /> <TextView android:id="@+id/tv_sign" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:text="标记" /> </LinearLayout>
child.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray" android:gravity="center_vertical" android:orientation="horizontal"> <CheckBox android:id="@+id/cb_child" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_marginLeft="40dp" android:layout_marginTop="30dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tv_content" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="20dp" android:text="什么手机" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/tv_pri" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="¥3000.00" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical"> <ImageView android:id="@+id/iv_jian" android:layout_width="20dp" android:layout_height="20dp" android:src="@drawable/jian" /> <TextView android:id="@+id/tv_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:paddingBottom="2dp" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="2dp" android:text="1" /> <ImageView android:id="@+id/iv_add" android:layout_width="20dp" android:layout_height="20dp" android:layout_marginLeft="5dp" android:src="@drawable/jia" /> </LinearLayout> </LinearLayout> <TextView android:id="@+id/tv_del" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="删除" /> </LinearLayout>