效果
一、MainActivty布局
<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"
tools:context=".MainActivity"
android:orientation="vertical">
<ExpandableListView
android:id="@+id/expandableLV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="15dp">
<CheckBox
android:id="@+id/isCheckAll_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全选"
android:padding="15dp"/>
<TextView
android:id="@+id/goodsPrice_main"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:text="商品总价:¥ 0 元"
android:textSize="20sp"
android:textColor="#000"/>
<Button
android:id="@+id/closing_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="结算(0)"/>
</LinearLayout>
</LinearLayout>
需要2个布局一个商家的布局一个商品的布局
商家
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<CheckBox
android:id="@+id/goods_addck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginLeft="35dp"
android:focusable="false"/>
<TextView
android:id="@+id/goods_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="商家1"
android:textColor="#000"
android:textSize="25sp"
android:padding="15dp"/>
</LinearLayout>
商品
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/child_ck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:layout_marginLeft="55dp"
android:layout_gravity="center"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center"/>
<LinearLayout
android:layout_width="180dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:padding="15dp">
<TextView
android:id="@+id/child_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="简介"/>
<TextView
android:id="@+id/child_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="价钱"/>
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.wjh.wangjiahui.view.Subtractor
android:id="@+id/child_subtractor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_alignParentRight="true"/>
</RelativeLayout>
</LinearLayout>
需要一个自定义的布局
选用组合式自定义布局
创建开始
/**
* date:2018/11/21
* author:王加辉(家辉辉辉)
* function:加减器自定义控件
*/
public class Subtractor extends LinearLayout implements View.OnClickListener {
private TextView numberText;
public Subtractor(Context context) {
this(context,null);
}
public Subtractor(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public Subtractor(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化操作
initView(context);
}
private void initView(Context context) {
//加载自定义控件布局
View view = View.inflate(context, R.layout.subtractor_item, this);
//找控件
Button jian = view.findViewById(R.id.jian_subItem);
Button jia = view.findViewById(R.id.jia_subItem);
numberText = view.findViewById(R.id.number_subItem);
//非常需要注意的一步,如果不写点击事件没效果
jian.setOnClickListener(this);
jia.setOnClickListener(this);
}
private int number = 1;
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.jian_subItem://-
if(number > 1 ){
-- number ;
numberText.setText(number + "");
//往接口中存数据
if(mSubtractorInterface != null){
mSubtractorInterface.setNumberListener(number);
}
}else{
Toast.makeText(getContext(), "不能再少了", Toast.LENGTH_SHORT).show();
}
break;
case R.id.jia_subItem://+
if(number < 10){
++ number;
numberText.setText(number +"");
//往接口中存数据
if(mSubtractorInterface != null){
mSubtractorInterface.setNumberListener(number);
}
}else{
Toast.makeText(getContext(), "别加了亲,爆了", Toast.LENGTH_SHORT).show();
}
break;
}
}
//创建接口
public interface SubtractorInterface{
void setNumberListener(int num);
}
//声明接口
private SubtractorInterface mSubtractorInterface;
//暴露方法
public void setSubtractorInterface(SubtractorInterface subtractorInterface){
mSubtractorInterface = subtractorInterface;
}
//很重要的一步set、get方法
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
numberText.setText(""+number);
}
}
自定义布局Iten
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/jian_subItem"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="-"
android:textSize="25sp"/>
<TextView
android:id="@+id/number_subItem"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:padding="15dp"
android:gravity="center"
android:text="1"
android:textSize="15sp"
android:textColor="#000"/>
<Button
android:id="@+id/jia_subItem"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="+"
android:textSize="25sp"/>
</LinearLayout>
okHttp的工具类封装就不写了
下面适配器
/**
* date:2018/11/21
* author:王加辉(家辉辉辉)
* function:BaseExpandableListAdapter适配器
*/
public class MyExLVAdapter extends BaseExpandableListAdapter {
private List<NetWorkDataBean.DataBean> mData;
private Context mContext;
public MyExLVAdapter(List<NetWorkDataBean.DataBean> data, Context context) {
mData = data;
mContext = context;
}
@Override
public int getGroupCount() {
return mData == null ? 0 : mData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return mData.get(groupPosition) == null ? 0 : mData.get(groupPosition).getList().size();
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
ViewHolder_group vh_group ;
if(convertView == null){
convertView = View.inflate(parent.getContext(), R.layout.group_item,null);
vh_group = new ViewHolder_group(convertView);
}else{
vh_group = (ViewHolder_group) convertView.getTag();
}
//设置内容
NetWorkDataBean.DataBean dataBean = mData.get(groupPosition);
vh_group.setData(dataBean,groupPosition);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ViewHolder vh_child ;
if(convertView == null){
convertView = View.inflate(parent.getContext(),R.layout.child_item,null);
vh_child = new ViewHolder(convertView);
}else {
vh_child = (ViewHolder) convertView.getTag();
}
//添加数据
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(groupPosition).getList();
NetWorkDataBean.DataBean.ListBean listBean = list.get(childPosition);
vh_child.setList(listBean,groupPosition,childPosition);
return convertView;
}
//优化
class ViewHolder_group{
CheckBox addCk;
TextView gName;
//构造方法
public ViewHolder_group(View viewItem){
addCk = viewItem.findViewById(R.id.goods_addck);
gName = viewItem.findViewById(R.id.goods_name);
viewItem.setTag(this);
}
//设置内容
public void setData(NetWorkDataBean.DataBean dataBean, final int groupPosition){
//店名
gName.setText(dataBean.getSellerName());
//根据当前所有的商品,判断商家CheckBox是否选中
boolean isCheckbox = changeGoodsCk(groupPosition);
//根据 isCheckbox 设置是否选中
addCk.setChecked(isCheckbox);
//点击事件
addCk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mMyExLvaInterface.gooderCheckBoxListener(groupPosition);
}
});
}
}
//子
class ViewHolder{
CheckBox ck;
TextView name,price;
Subtractor subtractor;
ImageView image;
private String substring;
public ViewHolder(View viewItem){
ck = viewItem.findViewById(R.id.child_ck);
name = viewItem.findViewById(R.id.child_name);
price = viewItem.findViewById(R.id.child_price);
subtractor = viewItem.findViewById(R.id.child_subtractor);
image = viewItem.findViewById(R.id.imageView);
viewItem.setTag(this);
}
public void setList(NetWorkDataBean.DataBean.ListBean listBean, final int groupPosition, final int childPosition){
String images = listBean.getImages();
if(images.indexOf("|") != -1){
substring = images.substring(0, images.indexOf("|"));
Picasso.with(mContext).load(substring).into(image);
}else{
Picasso.with(mContext).load(substring).into(image);
}
//因为数据中有选中的数据
ck.setChecked(listBean.getSelected() == 1);
name.setText(listBean.getTitle());
price.setText(listBean.getPrice() + "");
//为自定义控件设置数量
subtractor.setNumber(listBean.getNum());
//点击事件
ck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mMyExLvaInterface.goodsCheckBoxListener(groupPosition,childPosition);
}
});
//回调自定义控件
subtractor.setSubtractorInterface(new Subtractor.SubtractorInterface() {
@Override
public void setNumberListener(int num) {
mMyExLvaInterface.subChangeListener(groupPosition,childPosition,num);
}
});
}
}
//购物车最外面一层的逻辑
//判断商家的单选框的状态
public boolean changeGoodsCk(int groupPosition){
NetWorkDataBean.DataBean dataBean = mData.get(groupPosition);
List<NetWorkDataBean.DataBean.ListBean> list = dataBean.getList();
for (NetWorkDataBean.DataBean.ListBean listBean : list) {
int selected = listBean.getSelected();
//如果有一个商品未选中那么就商家单选框就未选中
if(selected == 0){
return false;
}
}
return true;
}
//判断底部单选框的状态
public boolean changeBottom(){
for(int x=0;x<mData.size();x++){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(x).getList();
for(int j=0 ; j<list.size();j++){
NetWorkDataBean.DataBean.ListBean listBean = list.get(j);
if(listBean.getSelected() == 0){
return false;
}
}
}
return true;
}
//计算商品的总价
public float countPrice(){
float sumPrice = 0;
for(int x=0;x<mData.size();x++){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(x).getList();
for(int j=0;j<list.size();j++){
NetWorkDataBean.DataBean.ListBean listBean = list.get(j);
if(listBean.getSelected() == 1){
//得到数量和单价
int num = listBean.getNum();
float price = listBean.getPrice();
//计算
sumPrice += num*price;
}
}
}
return sumPrice;
}
//获取商品的数量
public int goodsNum(){
int sumNum = 0;
for(int x=0;x<mData.size();x++){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(x).getList();
for(int j=0;j<list.size();j++){
if(list.get(j).getSelected() == 1){
int num = list.get(j).getNum();
sumNum += num ;
}
}
}
return sumNum;
}
/*
* 根据用户的交互,改变复选框的显示
* */
//根据商家单选框改变商品的单选框
public void changeGoods_GoodsAllCk(int groupPosition,boolean isCheckbox){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(groupPosition).getList();
//遍历所有的商品
for(int x=0;x<list.size();x++){
NetWorkDataBean.DataBean.ListBean listBean = list.get(x);
listBean.setSelected(isCheckbox ? 1 : 0);
}
}
//根据商家子条目的全部点击改变商家的单选框状态
public void changeGoods_GooderCk(int groupPosition,int childPosition){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(groupPosition).getList();
NetWorkDataBean.DataBean.ListBean listBean = list.get(childPosition);
listBean.setSelected(listBean.getSelected() == 0 ? 1 : 0);
}
//底部全选框
public void changeBottomAllCk(boolean selected){
for(int x=0;x<mData.size();x++){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(x).getList();
for(int j=0;j<list.size();j++){
NetWorkDataBean.DataBean.ListBean listBean = list.get(j);
listBean.setSelected(selected ? 1: 0);
}
}
}
//点击加减号的时候改变里面的值
public void changeSubValue(int groupPosition,int childPosition,int num){
List<NetWorkDataBean.DataBean.ListBean> list = mData.get(groupPosition).getList();
NetWorkDataBean.DataBean.ListBean listBean = list.get(childPosition);
listBean.setNum(num);
}
//创建接口
public interface MyExLvaInterface{
/**
* 当商家的checkBox点击的时候回调
* */
void gooderCheckBoxListener(int groupPosition);
/**
* 当商品的CheckBox点击时候回调
* */
void goodsCheckBoxListener(int groupPosition,int childPosition);
/**
* 当点击加减号的时候回调
* */
void subChangeListener(int groupPosition,int childPosition,int number);
}
//声明接口
private MyExLvaInterface mMyExLvaInterface;
//暴露方法
public void setMyExLvaInterface(MyExLvaInterface myExLvaInterface){
mMyExLvaInterface = myExLvaInterface;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
@Override
public Object getGroup(int groupPosition) {
return null;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
@Override
public long getGroupId(int groupPosition) {
return 0;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
@Override
public boolean hasStableIds() {
return false;
}
}
MainActivity代码
public class MainActivity extends AppCompatActivity {
private ExpandableListView mExpandableListView;
private CheckBox mIsCheckAll;
private TextView mGoodsPrice;
private Button mClosing;
private String strUrl = "http://www.zhaoapi.cn/product/getCarts";
private MyExLVAdapter mMAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//找控件
initView();
//初始化数据
initData();
}
/*
* 加载数据
* */
private void initData() {
//创建Presenter层
GoodsPresenter presenter = new GoodsPresenter();
//创建Map集合
HashMap<String, String> map = new HashMap<>();
map.put("uid","71");
presenter.NetWorkModel(strUrl, map, new OkHttpUtilsInterface() {
@Override
public void failure(Exception e) {
Toast.makeText(MainActivity.this, "数据加载错误", Toast.LENGTH_SHORT).show();
}
@Override
public void success(String json) {
NetWorkDataBean netWorkDataBean = new Gson().fromJson(json, NetWorkDataBean.class);
//判断请求是否成功
if("0".equals(netWorkDataBean.getCode())){
List<NetWorkDataBean.DataBean> data = netWorkDataBean.getData();
//设置适配器
mMAdapter = new MyExLVAdapter(data, MainActivity.this);
//先更新ui
changeAllUi();
//回调接口
mMAdapter.setMyExLvaInterface(new MyExLVAdapter.MyExLvaInterface() {
@Override
public void gooderCheckBoxListener(int groupPosition) {
boolean changeGoodsCk = mMAdapter.changeGoodsCk(groupPosition);
mMAdapter.changeGoods_GoodsAllCk(groupPosition,!changeGoodsCk);
mMAdapter.notifyDataSetChanged();
changeAllUi();
}
@Override
public void goodsCheckBoxListener(int groupPosition, int childPosition) {
mMAdapter.changeGoods_GooderCk(groupPosition,childPosition);
mMAdapter.notifyDataSetChanged();
changeAllUi();
}
@Override
public void subChangeListener(int groupPosition, int childPosition, int number) {
mMAdapter.changeSubValue(groupPosition,childPosition,number);
mMAdapter.notifyDataSetChanged();
changeAllUi();
}
});
mExpandableListView.setAdapter(mMAdapter);
for(int x=0 ; x<data.size();x++){
mExpandableListView.expandGroup(x);
}
}else{
Toast.makeText(MainActivity.this, "请求网络失败", Toast.LENGTH_SHORT).show();
}
}
});
}
/*
* 初始化控件
* */
private void initView() {
mExpandableListView = findViewById(R.id.expandableLV);
mIsCheckAll = findViewById(R.id.isCheckAll_main);
mGoodsPrice = findViewById(R.id.goodsPrice_main);
mClosing = findViewById(R.id.closing_main);
//结算点击事件
mClosing.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "恭喜你,没结算成功", Toast.LENGTH_SHORT).show();
}
});
//全选
mIsCheckAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean bottomCK = mMAdapter.changeBottom();
mMAdapter.changeBottomAllCk(!bottomCK);
mMAdapter.notifyDataSetChanged();
changeAllUi();
}
});
}
//刷新的方法
private void changeAllUi(){
//判断底部是否全部点击
boolean bottom = mMAdapter.changeBottom();
mIsCheckAll.setChecked(bottom);
//计算总价
float price = mMAdapter.countPrice();
mGoodsPrice.setText("总价:¥"+price+"元");
//计算数量
int goodsNum = mMAdapter.goodsNum();
mClosing.setText("结算("+goodsNum+")");
}
}