網絡封裝見:https://blog.csdn.net/biggrand/article/details/79191213
1.自定義封裝一個購物車二級列表:
/**
*
* 購物車的二級列表
* 在購物車的佈局中引用
*/
public class CartExpandableListView extends ExpandableListView {
public CartExpandableListView(Context context) {
super(context);
}
public CartExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CartExpandableListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 重寫測量的方法
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, height);
}
}
2.MVP模式:
M層:
public class ShopCartModel {
private IShopCartPre iShopCartPre;
public ShopCartModel(IShopCartPre iShopCartPre){
this.iShopCartPre = iShopCartPre;
}
public void getCartData(String url){
Map<String,String> map = new HashMap<>();
map.put("uid","2845");
map.put("source","android");
RetrofitHelper.getApiService(Api.YU_API).get(url,map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
ShopCartBean shopCartBean = new Gson().fromJson(s, ShopCartBean.class);
iShopCartPre.onSuccess(shopCartBean);
}
@Override
public void onError(Throwable e) {
Log.e("shopcartmodel","錯誤是:"+e);
}
@Override
public void onComplete() {
}
});
}
}
P層:
public class ShopCartPresenter implements IShopCartPre {
private ShopCartModel shopCartModel;
private IShopCartView iShopCartView;
public ShopCartPresenter(){
shopCartModel = new ShopCartModel(this);
}
public void attachView(IShopCartView iShopCartView){
this.iShopCartView = iShopCartView;
}
public void dettachView(){
if (iShopCartView != null){
iShopCartView = null;
}
}
public void getCartData(String url){
shopCartModel.getCartData(url);
}
@Override
public void onSuccess(ShopCartBean shopCartBean) {
iShopCartView.onSuccess(shopCartBean);
}
}
3.在購物車主頁面進行一系列操作:
public class MainActivity extends AppCompatActivity implements IShopCartView, View.OnClickListener {
@BindView(R.id.rl1)
RelativeLayout rl1;
@BindView(R.id.cartTwoListView)
CartExpandableListView cartTwoListView;
@BindView(R.id.sl1)
ScrollView sl1;
@BindView(R.id.progressBar)
RelativeLayout progressBar;
@BindView(R.id.check_all)
CheckBox checkAll;
@BindView(R.id.text_total)
TextView textTotal;
@BindView(R.id.text_buy)
TextView textBuy;
private ShopCartPresenter shopCartPresenter;
private List<ShopCartBean.DataBean> cartList;
private CartAdapter adapter;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
CountPriceBean countPriceBean = (CountPriceBean) msg.obj;
textTotal.setText("合計:¥" + countPriceBean.getPriceString());
textBuy.setText("去結算(" + countPriceBean.getCount() + ")");
}
}
};
private ShopCartBean shopCartBean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@Override
protected void onResume() {
super.onResume();
shopCartPresenter = new ShopCartPresenter();
shopCartPresenter.attachView(this);
shopCartPresenter.getCartData(Api.SelectCart_Api);
//1去掉二級列表默認的顯示器
cartTwoListView.setGroupIndicator(null);
//2剛進入頁面時讓progressBar顯示
progressBar.setVisibility(View.VISIBLE);
//點擊全選按鈕
checkAll.setOnClickListener(this);
}
/**
* 重寫查詢購物車數據的方法
*
* @param shopCartBean
*/
@Override
public void onSuccess(final ShopCartBean shopCartBean) {
this.shopCartBean = shopCartBean;
runOnUiThread(new Runnable() {
@Override
public void run() {
//3得到購物車的一級列表
cartList = shopCartBean.getData();
progressBar.setVisibility(View.GONE);
//如果購物車有東西時,設置適配器等配置
if (cartList!=null) {
Toast.makeText(MainActivity.this, shopCartBean.getMsg(), Toast.LENGTH_SHORT).show();
//4設置適配器
adapter = new CartAdapter(MainActivity.this, shopCartBean, progressBar, shopCartPresenter, handler);
cartTwoListView.setAdapter(adapter);
//5展開二級列表 才能拿到子條目的數據
for (int i = 0; i < cartList.size(); i++) {
cartTwoListView.expandGroup(i);
}
//6設置組的初始狀態
for (int i = 0; i < cartList.size(); i++) {
//先找出組中所有的孩子
List<ShopCartBean.DataBean.ListBean> childList = cartList.get(i).getList();
//根據孩子的狀態判斷組的狀態是否選中
cartList.get(i).setGroupCheck(isAllChildInGroupCheck(childList));
}
//7設置全選反選的控制
checkAll.setChecked(isAllGroupCheck(cartList));
//8設置價錢和數量的變化
adapter.sendPriceAndCount();
} else {
Toast.makeText(MainActivity.this, shopCartBean.getMsg(), Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* 全選反選的設置
*
* @param cartList
* @return
*/
private boolean isAllGroupCheck(List<ShopCartBean.DataBean> cartList) {
for (int i = 0; i < cartList.size(); i++) {
//如果有一個父類沒有選中,返回false
if (!cartList.get(i).isGroupChecked()) {
return false;
}
}
return true;
}
/**
* 根據孩子的狀態設置組的狀態是否選中
*
* @param childList
*/
private boolean isAllChildInGroupCheck(List<ShopCartBean.DataBean.ListBean> childList) {
for (int i = 0; i < childList.size(); i++) {
//只要有一個孩子沒有選中,那就返回false Selected==0 表示沒有選中
if (childList.get(i).getSelected() == 0) {
return false;
}
}
//如果孩子全都選中,name返回true,表示組選中
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (shopCartPresenter == null) {
shopCartPresenter.dettachView();
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.check_all:
//根據選擇狀態判斷是全選還是反選
adapter.setAllCheck(checkAll.isChecked());
break;
default:
break;
}
}
}
activity佈局:重點注意自定義佈局的路徑。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rl1"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="購物車"
android:textSize="26sp" />
</RelativeLayout>
<ScrollView
android:id="@+id/sl1"
android:layout_below="@+id/rl1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--二級購物車列表-->
<wuweixiong.bwie.com.cartexam2.Util.custom.CartExpandableListView
android:id="@+id/cartTwoListView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</wuweixiong.bwie.com.cartexam2.Util.custom.CartExpandableListView>
</LinearLayout>
</ScrollView>
<RelativeLayout
android:id="@+id/progressBar"
android:visibility="gone"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<LinearLayout
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#fff"
android:orientation="horizontal">
<CheckBox
android:id="@+id/check_all"
android:layout_width="40dp"
android:gravity="center"
android:layout_height="40dp" />
<TextView
android:id="@+id/text_total"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="合計:¥0.00"/>
<TextView
android:id="@+id/text_buy"
android:layout_width="0dp"
android:layout_weight="1"
android:textColor="#fff"
android:layout_height="match_parent"
android:gravity="center"
android:background="#f00"
android:layout_marginLeft="10dp"
android:text="去計算(0)"/>
</LinearLayout>
</RelativeLayout>
4.購物車的二級列表適配器
public class CartAdapter extends BaseExpandableListAdapter {
private static final String TAG = "cartadapter";
private ShopCartBean shopCartBean;
private Handler handler;
private ShopCartPresenter shopCartPresenter;
private RelativeLayout progressBar;
private Context context;
private int childIndex;
private int allIndex;
public CartAdapter(Context context, ShopCartBean shopCartBean, RelativeLayout progressBar, ShopCartPresenter shopCartPresenter, Handler handler) {
this.context = context;
this.shopCartBean = shopCartBean;
this.progressBar = progressBar;
this.shopCartPresenter = shopCartPresenter;
this.handler = handler;
}
@Override
public int getGroupCount() {
return shopCartBean.getData().size();
}
@Override
public int getChildrenCount(int i) {
return shopCartBean.getData().get(i).getList().size();
}
@Override
public Object getGroup(int i) {
return shopCartBean.getData().get(i);
}
@Override
public Object getChild(int i, int i1) {
return shopCartBean.getData().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 true;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
@Override
public View getGroupView(final int i, boolean b, View view, ViewGroup viewGroup) {
final GroupHolder holder;
if (view == null) {
holder = new GroupHolder();
//加載佈局
view = View.inflate(context, R.layout.group_item, null);
//找到控件
holder.checkBox = view.findViewById(R.id.check_group);
holder.textView = view.findViewById(R.id.text_group);
view.setTag(holder);
} else {
holder = (GroupHolder) view.getTag();
}
//賦值
final ShopCartBean.DataBean dataBean = shopCartBean.getData().get(i);
holder.textView.setText(dataBean.getSellerName());
//設置商家的選擇狀態
holder.checkBox.setChecked(dataBean.isGroupChecked());
//商家選擇狀態的改變
holder.checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//點擊時顯示progressbar
progressBar.setVisibility(View.VISIBLE);
//根據商家狀態一個一個更新,初始值爲0
childIndex = 0;
updateChildInGroup(holder.checkBox.isChecked(), dataBean);
}
});
return view;
}
/**
* 根據商家狀態改變子條目的狀態
*
* @param checked
* @param dataBean
*/
private void updateChildInGroup(final boolean checked, final ShopCartBean.DataBean dataBean) {
//1)先得到所有的子條目
ShopCartBean.DataBean.ListBean ziList = dataBean.getList().get(childIndex);
//2)因爲更新時所有的狀態都可能改變,所有都方法map集合裏
Map<String, String> map = new HashMap<>();
map.put("uid", "2845");
map.put("sellerid", String.valueOf(ziList.getSellerid()));
map.put("selected", String.valueOf(checked ? 1 : 0));
map.put("num", String.valueOf(ziList.getNum()));
map.put("pid", String.valueOf(ziList.getPid()));
//用retrofit+rxjava更新
RetrofitHelper.getApiService(Api.YU_API).get(Api.UpDataCar_Api, map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
childIndex++;
if (childIndex < dataBean.getList().size()) {
//循環更新
updateChildInGroup(checked, dataBean);
} else {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "updateChildInGroup" + e);
}
@Override
public void onComplete() {
}
});
}
@Override
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
ChildHolder holder;
if (view == null){
holder = new ChildHolder();
view = View.inflate(context,R.layout.child_item,null);
//找控件
holder.child_check = view.findViewById(R.id.child_check);
holder.child_image = view.findViewById(R.id.child_image);
holder.child_jia = view.findViewById(R.id.child_jia);
holder.child_jian = view.findViewById(R.id.child_jian);
holder.child_num = view .findViewById(R.id.child_num);
holder.child_del = view.findViewById(R.id.child_del);
holder.child_price = view.findViewById(R.id.child_price);
holder.child_title = view.findViewById(R.id.child_title);
view.setTag(holder);
}else {
holder = (ChildHolder) view.getTag();
}
//賦值
final ShopCartBean.DataBean.ListBean childBean = this.shopCartBean.getData().get(i).getList().get(i1);
//三元運算符判斷狀態
holder.child_check.setChecked(childBean.getSelected() == 0 ? false:true);
holder.child_title.setText(childBean.getTitle());
holder.child_image.setImageURI(childBean.getImages());
holder.child_price.setText("¥:"+childBean.getPrice());
holder.child_num.setText(childBean.getNum()+"");
holder.child_check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
progressBar.setVerticalGravity(View.VISIBLE);
Map<String, String> params = new HashMap();
params.put("uid", "2845");
params.put("sellerid", String.valueOf(childBean.getSellerid()));
params.put("pid", String.valueOf(childBean.getPid()));
params.put("selected", String.valueOf(childBean.getSelected() == 0 ? 1 : 0));
params.put("num", String.valueOf(childBean.getNum()));
RetrofitHelper.getApiService(Api.YU_API).get(Api.UpDataCar_Api, params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"getChildView:"+e);
}
@Override
public void onComplete() {
}
});
}
});
holder.child_jia.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
progressBar.setVerticalGravity(View.VISIBLE);
Map<String, String> params = new HashMap();
params.put("uid", "2845");
params.put("sellerid", String.valueOf(childBean.getSellerid()));
params.put("pid", String.valueOf(childBean.getPid()));
params.put("selected", String.valueOf(childBean.getSelected() == 0 ? 1 : 0));
params.put("num", String.valueOf(childBean.getNum()));
RetrofitHelper.getApiService(Api.YU_API).get(Api.UpDataCar_Api, params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"getChildView加:"+e);
}
@Override
public void onComplete() {
}
});
}
});
holder.child_jian.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int num = childBean.getNum();
if (num == 1) {
return;
}
progressBar.setVerticalGravity(View.VISIBLE);
Map<String, String> params = new HashMap();
params.put("uid", "2845");
params.put("sellerid", String.valueOf(childBean.getSellerid()));
params.put("pid", String.valueOf(childBean.getPid()));
params.put("selected", String.valueOf(childBean.getSelected()));
params.put("num", String.valueOf(num - 1));
RetrofitHelper.getApiService(Api.YU_API).get(Api.UpDataCar_Api, params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
});
holder.child_del.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
progressBar.setVerticalGravity(View.VISIBLE);
Map<String, String> params = new HashMap();
params.put("uid", "2845");
params.put("pid", String.valueOf(childBean.getPid()));
RetrofitHelper.getApiService(Api.YU_API).get(Api.DeleteCart_Api, params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
});
return view;
}
/**
* 設置價錢和數量的變化
*/
public void sendPriceAndCount() {
double price = 0;
int count = 0;
for (int i = 0; i < shopCartBean.getData().size(); i++) {
List<ShopCartBean.DataBean.ListBean> listBeans = this.shopCartBean.getData().get(i).getList();
for (int j = 0; j < listBeans.size(); j++) {
if (listBeans.get(j).getSelected() == 1) {
price = price + listBeans.get(j).getBargainPrice() * listBeans.get(j).getNum();
count += listBeans.get(j).getNum();
}
}
}
//double高精度,,,計算的時候可能會出現一串數字...保留兩位
DecimalFormat decimalFormat = new DecimalFormat("0.00");
String priceString = decimalFormat.format(price);
CountPriceBean countPriceBean = new CountPriceBean(priceString, count);
Message msg = Message.obtain();
msg.what = 1;
msg.obj = countPriceBean;
handler.sendMessage(msg);
}
public void setAllCheck(boolean checked) {
//創建一個大的結合,,,存放所有商品的數據
List<ShopCartBean.DataBean.ListBean> allList = new ArrayList<>();
for (int i = 0; i < shopCartBean.getData().size(); i++) {
List<ShopCartBean.DataBean.ListBean> listBeans = shopCartBean.getData().get(i).getList();
for (int j = 0; j < listBeans.size(); j++) {
allList.add(listBeans.get(j));
}
}
//顯示progress
progressBar.setVisibility(View.VISIBLE);
//遞歸更新....
allIndex = 0;
upDateAllChecked(allList, checked);
}
private void upDateAllChecked(final List<ShopCartBean.DataBean.ListBean> allList, final boolean checked) {
ShopCartBean.DataBean.ListBean listBean = allList.get(allIndex);
Map<String, String> params = new HashMap<>();
params.put("uid", "2845");
params.put("sellerid", String.valueOf(listBean.getSellerid()));
params.put("pid", String.valueOf(listBean.getPid()));
params.put("selected", String.valueOf(checked ? 1 : 0));
params.put("num", String.valueOf(listBean.getNum()));
RetrofitHelper.getApiService(Api.YU_API).get(Api.UpDataCar_Api, params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
allIndex++;
if (allIndex < allList.size()) {
upDateAllChecked(allList, checked);
} else {
shopCartPresenter.getCartData(Api.SelectCart_Api);
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
public class GroupHolder {
CheckBox checkBox;
TextView textView;
}
public class ChildHolder {
CheckBox child_check;
SimpleDraweeView child_image;
TextView child_title;
TextView child_price;
TextView child_jian;
TextView child_num;
TextView child_jia;
Button child_del;
}
}
child佈局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/child_check"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/child_image"
android:layout_width="100dp"
android:padding="10dp"
android:layout_height="100dp"
fresco:placeholderImage="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/child_title"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:text="標題"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/child_price"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textColor="#f00"
android:text="¥:0.00"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/child_jian"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="16sp"
android:text="-"/>
<TextView
android:id="@+id/child_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="16sp"
android:text="1"/>
<TextView
android:id="@+id/child_jia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="16sp"
android:text="+"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/child_del"
android:layout_width="50dp"
android:layout_height="match_parent"
android:text="刪除"
android:background="#f00"
android:textColor="#fff"/>
</LinearLayout>