图片与代码不符
购物车,无非就是对复选框的全选、反选、数量增减,计算价格的一些逻辑
本帖子需要有耐心的朋友和对于初学者比较适用,中高级资深玩家,会觉得比较Low了嘿嘿。
下面是购物车页面的布局
追加两个父布局页面和子布局页面
首先是父布局页面cart_group_item
其次是子布局页面cart_child_item
在这里,本人使用的是ExpandableListView二级列表展示的,相对来说,逻辑比较清晰一点
下面是适配器里面的主要逻辑代码和简单的MVP设计,没有抽取基类。
//父条目视图View
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
//使用ViewHolder进行条目优化
MyGroupViewHolder myGroupViewHolder = null;
//convertView条目复用
if (convertView == null) {
//获取父视图
convertView = LayoutInflater.from(context).inflate(R.layout.group_item, parent, false);
CheckBox cb = convertView.findViewById(R.id.group_cb);
TextView name = convertView.findViewById(R.id.group_name);
myGroupViewHolder = new MyGroupViewHolder(cb, name);
convertView.setTag(myGroupViewHolder);
} else {
myGroupViewHolder = (MyGroupViewHolder) convertView.getTag();
}
//初始化父条目数据
myGroupViewHolder.getGroup_cb().setChecked(list.get(groupPosition).isGroupFlag());
myGroupViewHolder.getGroup_name().setText(list.get(groupPosition).getSellerName());
//父条目复选框点击事件
myGroupViewHolder.getGroup_cb().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//把v强转成CheckBox并获取它的选中状态
CheckBox box = (CheckBox) v;
boolean boxChecked = box.isChecked();
//给父条目数据Bean赋值
list.get(groupPosition).setGroupFlag(boxChecked);
//判断当复选框选中的时候,记录选中一个
if (boxChecked) {
count++;
} else {
//当它未选中的时候,记录原来选中数如果大于0时的减一
if (count > 0) {
count--;
}
}
//获取到子条目数据集合
List childList = MyAdapter.this.list.get(groupPosition).getList();
for (int i = 0; i < childList.size(); i++) {
//遍历集合给子条目的复选框选中状态设为父条目复选框的选中状态,父条目及其子条目的全选和反选,
childList.get(i).setChildFlag(boxChecked);
}
//使用自定义接口把获取到的条目选中数量传出去
onGetCount.getCount(count);
//调用刷新适配器的方法
setNotifyDataSetChanged();
}
});
return convertView;
}
//子条目视图,优化方式同上,就不一一讲解了
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
MyChildViewHolder myChildViewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.child_item, parent, false);
CheckBox child_cb = convertView.findViewById(R.id.child_cb);
SimpleDraweeView child_simple = convertView.findViewById(R.id.child_simple);
TextView child_title = convertView.findViewById(R.id.child_title);
TextView child_scount = convertView.findViewById(R.id.child_scount);
TextView child_delete = convertView.findViewById(R.id.child_delete);
SumLayout sumLayout = convertView.findViewById(R.id.sumlayout);
myChildViewHolder = new MyChildViewHolder(child_cb, child_simple, child_title, child_scount, child_delete,sumLayout);
convertView.setTag(myChildViewHolder);
} else {
myChildViewHolder = (MyChildViewHolder) convertView.getTag();
}
//初始化子条目数据
final List childList = this.list.get(groupPosition).getList();
myChildViewHolder.getChild_cb().setChecked(childList.get(childPosition).isChildFlag());
String images = childList.get(childPosition).getImages().split("\\|")[0];
myChildViewHolder.getChild_simple().setImageURI(images);
myChildViewHolder.getChild_title().setText(childList.get(childPosition).getTitle());
myChildViewHolder.getChild_scount().setText(childList.get(childPosition).getSubhead());
//得到数据里面的购买数量
num = list.get(groupPosition).getList().get(childPosition).getNum();
//给视图赋值
myChildViewHolder.getSumLayout().setCount(num+"");
//自定义加减框点击事件
final MyChildViewHolder finalMyChildViewHolder1 = myChildViewHolder;
myChildViewHolder.getSumLayout().setOnDownSumLayoutListener(new SumLayout.OnDownSumLayouListener() {
@Override
public void onDownSumLayout() {
//得到改变后的购买数量
String count = finalMyChildViewHolder1.getSumLayout().getCount();
//转为int型
int i = Integer.parseInt(count);
//并重新给子条目数据的购买数量赋值
list.get(groupPosition).getList().get(childPosition).setNum(i);
//调用刷新适配器的方法
setNotifyDataSetChanged();
}
});
//删除购物车数据 目前仅仅是删除listview视图 没有删除数据
myChildViewHolder.getChild_delete().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List childList = MyAdapter.this.list.get(groupPosition).getList();
childList.remove(childPosition);
setNotifyDataSetChanged();
}
});
final MyChildViewHolder finalMyChildViewHolder = myChildViewHolder;
//子条目复选框点击事件
myChildViewHolder.getChild_cb().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//得到子条目复选框的选中状态
boolean checked = finalMyChildViewHolder.getChild_cb().isChecked();
//得到子条目数据集合
List childList = MyAdapter.this.list.get(groupPosition).getList();
// 把选中状态赋值给数据集合
childList.get(childPosition).setChildFlag(checked);
//判断当为选中状态时选中数量加一
if (checked) {
count++;
} else {//否则减一
if (count > 0) {
count--;
}
}
//设置标记flag 默认为true
boolean flag = true;
//遍历子条目数据里面的复选框状态,有一个为false,那么父条目数据复选框状态就为false
for (int i = 0; i < childList.size(); i++) {
boolean childFlag = childList.get(i).isChildFlag();
if (childFlag == false) {
flag = false;
}
}
//当子条目复选框全部选中时,父条目复选框,也选中
list.get(groupPosition).setGroupFlag(flag);
//使用自定义接口把获取到的条目选中数量传出去
onGetCount.getCount(count);
//调用刷新适配器的方法
setNotifyDataSetChanged();
}
});
return convertView;
}
/**
* 刷新适配器的方法
*/
public void setNotifyDataSetChanged() {
//刷洗适配器
notifyDataSetChanged();
//重新请求网络数据
CartPresenterImpl cartPresenter = new CartPresenterImpl();
//请求计算接口
cartPresenter.formJisuan(new CartModelImpl(cartPresenter), iCartView);
}
//复选框选中个数的内部接口
public interface OnGetCount {
void getCount(int count);
}
//访问接口的放发
public void setOnGetCount(OnGetCount onGetCount) {
this.onGetCount = onGetCount;
}
我这里使用的是Retrofit+RxJava+MVP进行请求网络数据比较繁琐。朋友,看到这里,已经很棒了。主要适配器的逻辑已经完成。下面是关于网络请求的代码
Model层接口
public interface ICartModel {
//获取购物车数据方法
void formCartDatas(Map params);
//获取购物车计算价格数据方法
void formCartJisuan(List data,ICartPresenter iCartPresenter);
}
Model层接口实现类
public class CartModelImpl implements ICartModel {
private static final String TAG = "CartModelImpl";
private final ICartPresenter iCartPresenter;
//构造方法得到P层的实例
public CartModelImpl(ICartPresenter iCartPresenter) {
this.iCartPresenter = iCartPresenter;
}
//获取购物车数据方法
@Override
public void formCartDatas(Map params) {
//得到网络请求工具类Retrofit+RxJava
NetWorkUtils netWorkUtils = NetWorkUtils.getNetWorkUtils();
RtrofitService rtrofitService = netWorkUtils.creatRequest(RtrofitService.class);
Observable cartBean = rtrofitService.getCartBean(params);
cartBean.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
//请求完成
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: 完成");
}
//请求失败
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: " + e.getMessage());
iCartPresenter.formDataError(e.getMessage());
}
//请求中
@Override
public void onNext(CartBean cartBean) {
Log.d(TAG, "onNext: " + cartBean);
String code = cartBean.getCode();
//根据code进行判断 如果code等于0为请求成功 否则请求失败
if (code.equals("0")) {
iCartPresenter.formDataSuccess(cartBean.getData());
} else {
iCartPresenter.formDataError(cartBean.getMsg());
}
}
});
}
//获取购物车计算价格数据方法 一定是View层返回的集合
@Override
public void formCartJisuan(List data,ICartPresenter iCartPresenter) {
//初始值为0 记录总价
double sum = 0;
//遍历父条目数据集合
for (int i = 0; i < data.size(); i++) {
//得到子条目数据集合
List childList = data.get(i).getList();
//遍历子条目数据集合
for (int j = 0; j < childList.size(); j++) {
//如果,子条目复选框为选中状态时,则累加总价
if (childList.get(j).isChildFlag()){
//得到总价sum 总价=数量*单价
sum+=childList.get(j).getNum()*childList.get(j).getPrice();
}
}
}
Log.d(TAG, "formCartJisuan: "+sum);
//把得到的总价传到Presenter层
iCartPresenter.getPrice(sum);
}
Presenter层接口
public interface ICartPresenter {
//获取Model层和View层方法 和构造方法效果一样
void formDataModelView(ICartModel iCartModel, ICartView iCartView);
//获取数据成功方法
void formDataSuccess(List data);
//获取数据失败方法
void formDataError(String error);
//获取计算总价方法
void formJisuan(ICartModel iCartModel,ICartView iCartView);
//的到总价方法
void getPrice(double price);
}
Presenter层接口实现类
public class CartPresenterImpl implements ICartPresenter {
private static final String TAG = "CartPresenterImpl";
private ICartView iCartView;
//获取Model层和View层方法 和构造方法效果一样
@Override
public void formDataModelView(ICartModel iCartModel, ICartView iCartView) {
//得到View层实例
this.iCartView = iCartView;
Map params = new HashMap<>();
params.put("uid",iCartView.getUid());
//调用Model层获取购物车数据方法
iCartModel.formCartDatas(params);
}
//获取数据成功方法
@Override
public void formDataSuccess(List data) {
Log.d(TAG, "formDataSuccess: "+data);
//调用view层获取数据成功的方法
iCartView.formCartViewSuccess(data);
}
//获取数据失败方法
@Override
public void formDataError(String error) {
Log.d(TAG, "formDataError: "+error);
//调用view层获取数据失败的方法
iCartView.formCaRTViewError(error);
}
//获取计算总价方法
@Override
public void formJisuan(ICartModel iCartModel, ICartView iCartView) {
this.iCartView = iCartView;
//调用Model层计算总价的方法
iCartModel.formCartJisuan(iCartView.getList(),this);
}
//得到总价方法
@Override
public void getPrice(double price) {
Log.d(TAG, "getPrice: "+price);
//把获取到的总价传递给View
iCartView.getSum(price);
}
}
View层接口
public interface ICartView {
//获取数据成功方法
void formCartViewSuccess(List data);
//获取数据失败方法
void formCaRTViewError(String error);
//返回UID方法
String getUid();
//获取总价方法
void getSum(double price);
//放回购物车数据方法
List getList();
}
MainActivity类View层实现类
public class MainActivity extends AppCompatActivity implements ICartView {
private static final String TAG = "MainActivity";
@BindView(R.id.main_back)
TextView mainBack;
@BindView(R.id.expandable)
ExpandableListView expandable;
@BindView(R.id.main_checkAll)
CheckBox mainCheckAll;
@BindView(R.id.main_sum)
TextView mainSum;
@BindView(R.id.main_pay)
TextView mainPay;
private List list;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用ButterKnife
ButterKnife.bind(this);
//初始化视图/数据
initViews();
}
private void initViews() {
//请求网络
CartPresenterImpl cartPresenter = new CartPresenterImpl();
cartPresenter.formDataModelView(new CartModelImpl(cartPresenter), MainActivity.this);
}
@OnClick({R.id.main_back, R.id.main_checkAll, R.id.main_pay})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.main_back:
Toast.makeText(this, "我点击了返回", Toast.LENGTH_SHORT).show();
break;
case R.id.main_checkAll://全选复选框点击事件
//得到全选框的选中状态
boolean checked = mainCheckAll.isChecked();
for (int i = 0; i < list.size(); i++) {
//遍历购物车数据得到子条目数据集合 把父条目复选框设为全选框状态
list.get(i).setGroupFlag(checked);
List childList = this.list.get(i).getList();
for (int j = 0; j < childList.size(); j++) {
//把子条目复选框设全选框状态
childList.get(j).setChildFlag(checked);
}
}
//刷洗适配器
myAdapter.notifyDataSetChanged();
//重新计算总价
CartPresenterImpl cartPresenter = new CartPresenterImpl();
//刷新总价
cartPresenter.formJisuan(new CartModelImpl(cartPresenter),this);
break;
case R.id.main_pay:
break;
}
}
// 获取购物车数据成功方法
@Override
public void formCartViewSuccess(List data) {
//把购物车数据提升作用域
this.list = data;
Log.d(TAG, "formCartViewSuccess: " + data);
//实例化Adapter
myAdapter = new MyAdapter(this, data, this);
//ExpandableListView设置适配器
expandable.setAdapter(myAdapter);
//调用adapter的复选框选中个数的内部接口
myAdapter.setOnGetCount(new MyAdapter.OnGetCount() {
@Override
public void getCount(int count) {
Log.d(TAG, "getCount: " + count);
//给TextView赋值
mainPay.setText("去支付(" + count + ")");
}
});
//展开子条目
int count = expandable.getCount();
for (int i = 0; i < count; i++) {
expandable.expandGroup(i);
}
}
//获取购物车数据失败方法
@Override
public void formCaRTViewError(String error) {
Log.d(TAG, "formCaRTViewError: " + error);
}
//返回Uid方法
@Override
public String getUid() {
return 71 + "";
}
//获取总价方法
@Override
public void getSum(double price) {
Log.d(TAG, "getSum: " + price);
mainSum.setText("合计:¥" + price);
}
//返回购物车数据方法
@Override
public List getList() {
return list;
}
}
当然,还要有自定义加减框了 SumLayout
public class SumLayout extends LinearLayout implements View.OnClickListener {
private TextView sub;
private TextView count;
private TextView add;
private OnDownSumLayouListener onDownSumLayoutListener;
//自定义View的构造方法
public SumLayout(Context context) {
this(context, null);
}
public SumLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SumLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//加载视图
View view = View.inflate(context, R.layout.sumlayout, this);
//获取控件
sub = view.findViewById(R.id.sub);
count = view.findViewById(R.id.count);
add = view.findViewById(R.id.add);
//注册点击事件
sub.setOnClickListener(this);
add.setOnClickListener(this);
}
//点击事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sub://数量减减
//得到数量
String ss = count.getText().toString();
//转为int型
int i = Integer.parseInt(ss);
//减减
i--;
//判断当i大于等于0时给TextView赋值
if (i >= 0) {
setCount(i + "");
//调用自定义接口点击事件
onDownSumLayoutListener.onDownSumLayout();
}
break;
case R.id.add://数量加加
//获取数量
String s = count.getText().toString();
//转为int型
int i1 = Integer.parseInt(s);
//数量加加
i1++;
//给数量TextView赋值
setCount(i1 + "");
//调用自定义接口点击事件
onDownSumLayoutListener.onDownSumLayout();
break;
}
}
//给数量TextView赋值的方法
public void setCount(String counts) {
count.setText(counts);
}
//获取数量方法
public String getCount() {
return count.getText().toString();
}
//自定义接口点击事件
public interface OnDownSumLayouListener {
void onDownSumLayout();
}
//外部访问接口的方法
public void setOnDownSumLayoutListener(OnDownSumLayouListener onDownSumLayoutListener) {
this.onDownSumLayoutListener = onDownSumLayoutListener;
}
}
别着急下面是自定义组合控件的xml文件 sumlayout.xml
还有自定义背景的xml文件 sumbgcolor.xml
不过,有一个BUG还没有解决,在去结算按钮括号里面的数量不能根据全选而改变和它会多选的Bug,解决了以后会追加在下面。