购物车实现机制:
- 使用二级列表展示数据
- 设置全选全不选以及父条目子条目联动的效果
- 实现加减数量的改变
- 计算总价并更新
详细讲解:
- 使用控件ExpandableListView来展示二级列表数据
- 创建类继承BaseExpandableListAdapter来写适配器的操作
- 使用自定义view组合控件实现加减和数量显示的效果
- 子条目和父条目都设置CheckBox
- 实现CheckBox关联(这里需要一些稍微复杂的逻辑操作)
1.当父条目选中那么此父条目相对应的子条目也要选中
2.当子条目全部选中的时候对应的父条目也要设置选中状态
3.当父条目选中的时候全选按钮也是选中状态
4.当全选的时候父条目就为选中状态,但是还要关联子控件也要一块选中
5.不管每次点击父条目还是子条目的CheckBox都要做改变数据的操作,所以需要刷新适配器
6.点击CheckBox为选中状态的时候需要将总价和总数量计算出来
7.赋值肯定是一个刷新UI的操作,需要每次点击都要重新赋值
简单的购物车的效果如下图:
虽然这个效果有点丑,但是里边还是有些逻辑性的代码
这里有一些MVP和抽取基类的一些东西
下面展示一下代码
MainActivity
public class MainActivity extends BaseActivity implements IView, View.OnClickListener{
private IPresenterImpl iPresenter;
private ExpandableListView mExpandableList;
private String mUrl = "http://www.wanandroid.com/tools/mockapi/6523/restaurant-list";
private MyAdapter adapter;
private CheckBox mAllCheck;
private TextView mAllContent;
private TextView mAllPrice;
private boolean boo;
@Override
protected int getLayout() {
return R.layout.activity_main;
}
@Override
protected void initViews() {
mExpandableList = findViewById(R.id.main_expandale_list);
mAllCheck = findViewById(R.id.main_check_allCheck);
mAllContent = findViewById(R.id.main_text_allContent);
mAllPrice = findViewById(R.id.main_text_allPrice);
}
@Override
protected void onClicks() {
mAllCheck.setOnClickListener(this);
}
@Override
protected void progress() {
iPresenter = new IPresenterImpl(this);
iPresenter.getString(mUrl);
}
@Override
public void getData(Object data) {
GroupAndChildBean bean = (GroupAndChildBean) data;
List<GroupAndChildBean.DataBean> list = bean.getData();
adapter = new MyAdapter(list, MainActivity.this);
mExpandableList.setAdapter(adapter);
//接口回调得到总价格和总数量(这里我设置的是每次点击的时候都会传一次值,便于我们更新UI)
adapter.setInter(new Inter_getData() {
@Override
public void getData(Object data) {
boolean da = (boolean) data;
if(da==true){
mAllCheck.setChecked(true);
}else{
mAllCheck.setChecked(false);
}
}
@Override
public void getNumPrice(Object price) {
mAllPrice.setText("总价格:"+price);
}
@Override
public void getNumContent(Object content) {
mAllContent.setText("总数量:"+content);
}
});
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.main_check_allCheck:
if(mAllCheck.isChecked()){
boo = true;
//当点击全选的时候联动父控件和子控件
adapter.setAll(boo);
//当全选的时候就是判断全部的价格和全部的数量
float adapterPrice = adapter.getPrice();
int adapterContent = adapter.getContent();
mAllContent.setText("总数量:"+adapterContent);
mAllPrice.setText("总价格:"+adapterPrice);
}else{
boo = false;
//默认赋值
mAllContent.setText("总数量:"+0);
mAllPrice.setText("总价格:"+0);
//当点击全选的时候联动父控件和子控件
adapter.setAll(boo);
}
break;
}
}
}
适配器
public class MyAdapter extends BaseExpandableListAdapter {
private List<GroupAndChildBean.DataBean> mList;
private Context mContent;
private Inter_getData inter_getData;
//定义有参构造,需要我们从MainActivity传数据
public MyAdapter(List<GroupAndChildBean.DataBean> mList, Context mContent) {
this.mList = mList;
this.mContent = mContent;
}
//定义接口
public void setInter(Inter_getData inter_getData){
this.inter_getData = inter_getData;
}
//父级的Holder
class MyGroupHplder{
public CheckBox group_checkBox;
public TextView group_name;
};
//子级的Holder
class MyChildHplder{
public CheckBox child_checkBox;
public ImageView child_img;
public TextView child_name,child_price;
public zdy_NumContent child_content;
};
//父控件的条目数量
@Override
public int getGroupCount() {
return mList.size();
}
//子控件的条目数量
@Override
public int getChildrenCount(int i) {
return mList.get(i).getSpus().size();
}
@Override
public Object getGroup(int i) {
return null;
}
@Override
public Object getChild(int i, int i1) {
return null;
}
@Override
public long getGroupId(int i) {
return 0;
}
@Override
public long getChildId(int i, int i1) {
return 0;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return false;
}
//父控件优化、赋值、和相应操作
@Override
public View getGroupView(final int i, boolean b, View view, ViewGroup viewGroup) {
MyGroupHplder myGroupHplder;
if(view==null){
myGroupHplder = new MyGroupHplder();
view = View.inflate(mContent, R.layout.item_group, null);
myGroupHplder.group_checkBox = view.findViewById(R.id.item_group_check);
myGroupHplder.group_name = view.findViewById(R.id.item_group_name);
view.setTag(myGroupHplder);
}else{
myGroupHplder = (MyGroupHplder) view.getTag();
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
//因为我们在每次点击checkBox的时候才会改变状态,判断我们的方法里的条件是否成立
myGroupHplder.group_checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setOnClickGroup(i);
//接口回调(将是否全选、总价格、总数量的值通过接口回调传入我们的MainActivity)
boolean onAll = OnAll();
float price = getPrice();
int content = getContent();
if(inter_getData!=null){
inter_getData.getData(onAll);
inter_getData.getNumPrice(price);
inter_getData.getNumContent(content);
}
//点击完之后肯定会将值改变所以需要我们每次点击的时候做刷新适配器的操作
notifyDataSetChanged();
}
});
//赋值
myGroupHplder.group_checkBox.setChecked(mList.get(i).getGroup_checked());
myGroupHplder.group_name.setText(mList.get(i).getName());
return view;
}
//子控件优化、赋值、和相应操作
@Override
public View getChildView(final int i,final int i1, boolean b, View view, ViewGroup viewGroup) {
MyChildHplder myChildHplder;
if(view==null){
myChildHplder = new MyChildHplder();
view = View.inflate(mContent, R.layout.item_child, null);
myChildHplder.child_checkBox = view.findViewById(R.id.item_child_check);
myChildHplder.child_img = view.findViewById(R.id.item_child_img);
myChildHplder.child_name = view.findViewById(R.id.item_child_name);
myChildHplder.child_price = view.findViewById(R.id.item_child_price);
myChildHplder.child_content = view.findViewById(R.id.item_child_content);
view.setTag(myChildHplder);
}else{
myChildHplder = (MyChildHplder) view.getTag();
}
final List<GroupAndChildBean.DataBean.SpusBean> list = mList.get(i).getSpus();
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
myChildHplder.child_checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//点击子控件设置选中和未选中状态
setOnClickChild(i, i1);
//这个方法是判断当子控件全部选中的时候给父控件也选中
setAllChild(i);
//下面将数据传入MainActivity
float price = getPrice();
int content = getContent();
if(inter_getData!=null){
inter_getData.getNumPrice(price);
inter_getData.getNumContent(content);
}
notifyDataSetChanged();
}
});
myChildHplder.child_checkBox.setChecked(list.get(i1).getChild_checked());
Picasso.get().load(list.get(i1).getPic_url()).into(myChildHplder.child_img);
myChildHplder.child_name.setText(list.get(i1).getName());
myChildHplder.child_price.setText(list.get(i1).getSkus().get(0).getPrice());
// myChildHplder.child_content.setText(list.get(i1).getPraise_num()+"");
myChildHplder.child_content.setAllNum(list.get(i1).getPraise_num()+"");
//这里我用的是自定义View实现后边的数量加的操作
myChildHplder.child_content.setJiaOnclick(new View.OnClickListener() {
@Override
public void onClick(View view) {
int praise_num = list.get(i1).getPraise_num();
praise_num++;
list.get(i1).setPraise_num(praise_num);
notifyDataSetChanged();
float price = getPrice();
int content = getContent();
if(inter_getData!=null){
inter_getData.getNumPrice(price);
inter_getData.getNumContent(content);
}
}
});
//这里我用的是自定义View实现后边的数量减的操作
myChildHplder.child_content.setJianOnClick(new View.OnClickListener() {
@Override
public void onClick(View view) {
int praise_num = list.get(i1).getPraise_num();
if(praise_num>0){
praise_num--;
list.get(i1).setPraise_num(praise_num);
}else{
Toast.makeText(mContent,"已经是最小数量了",Toast.LENGTH_SHORT).show();
praise_num = 0;
list.get(i1).setPraise_num(praise_num);
}
notifyDataSetChanged();
float price = getPrice();
int content = getContent();
if(inter_getData!=null){
inter_getData.getNumPrice(price);
inter_getData.getNumContent(content);
}
}
});
return view;
}
//父控件将父控件内的子控件全部选中
public void setOnClickGroup(int position){
if(mList.get(position).getGroup_checked()){
mList.get(position).setGroup_checked(false);
for (int i = 0; i < mList.get(position).getSpus().size(); i++) {
mList.get(position).getSpus().get(i).setChild_checked(false);
}
}else{
mList.get(position).setGroup_checked(true);
for (int i = 0; i < mList.get(position).getSpus().size(); i++) {
mList.get(position).getSpus().get(i).setChild_checked(true);
}
}
}
//子控件选中
public void setOnClickChild(int groupPosition,int childPosition){
GroupAndChildBean.DataBean.SpusBean bean = mList.get(groupPosition).getSpus().get(childPosition);
if(bean.getChild_checked()){
bean.setChild_checked(false);
}else{
bean.setChild_checked(true);
}
}
//当子控件全部选中的时候给父控件也选中
public void setAllChild(int groupPosition){
boolean boo = true;
for (int i = 0; i < mList.get(groupPosition).getSpus().size(); i++) {
GroupAndChildBean.DataBean.SpusBean bean = mList.get(groupPosition).getSpus().get(i);
if(!bean.getChild_checked()){
boo=false;
}
}
if(boo==true){
mList.get(groupPosition).setGroup_checked(true);
boolean onAll = OnAll();
if(inter_getData!=null){
inter_getData.getData(onAll);
}
}else{
mList.get(groupPosition).setGroup_checked(false);
boolean onAll = OnAll();
if(inter_getData!=null){
inter_getData.getData(onAll);
}
}
}
//当父控件全部选中的时候把全选按钮设置为选中状态
public void setAll(boolean allCheck){
if(allCheck==true){
for (int i = 0; i < mList.size(); i++) {
mList.get(i).setGroup_checked(!allCheck);
notifyDataSetChanged();
setOnClickGroup(i);
}
}else{
for (int i = 0; i < mList.size(); i++) {
mList.get(i).setGroup_checked(!allCheck);
notifyDataSetChanged();
setOnClickGroup(i);
}
}
}
当父控件全部选中的时候把全选按钮设置为选中状态
public boolean OnAll(){
boolean boo = true;
for (int i = 0; i < mList.size(); i++) {
if(!mList.get(i).getGroup_checked()){
boo = false;
}
}
return boo;
}
//获取总价格
public float getPrice(){
float zPrice = 0;
for (int i = 0; i < mList.size(); i++) {
List<GroupAndChildBean.DataBean.SpusBean> list = mList.get(i).getSpus();
for (int j = 0; j < list.size(); j++) {
if(list.get(j).getChild_checked()){
float price = Float.parseFloat(list.get(j).getSkus().get(0).getPrice());
int content = list.get(j).getPraise_num();
zPrice += content*price;
}
}
}
return zPrice;
}
//获取总数量
public int getContent(){
int zContent = 0;
for (int i = 0; i < mList.size(); i++) {
List<GroupAndChildBean.DataBean.SpusBean> list = mList.get(i).getSpus();
for (int j = 0; j < list.size(); j++) {
if(list.get(j).getChild_checked()){
int content = list.get(j).getPraise_num();
zContent += content;
}
}
}
return zContent;
}
}
接口回调
public interface Inter_getData<T> {
void getData(T data);
void getNumPrice(T price);
void getNumContent(T content);
}
自定义View组合控件实现加减的地方
public class zdy_NumContent extends LinearLayout{
private ImageView mImgJia;
private ImageView mImgJian;
private TextView mAllContent;
public zdy_NumContent(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.zdy_layout,this);
mImgJia = findViewById(R.id.layout_img_jia);
mImgJian = findViewById(R.id.layout_img_jian);
mAllContent = findViewById(R.id.layout_All_Content);
}
public void setJiaOnclick(OnClickListener onclick){
mImgJia.setOnClickListener(onclick);
}
public void setJianOnClick(OnClickListener onClick){
mImgJian.setOnClickListener(onClick);
}
public void setAllNum(String num){
mAllContent.setText(num);
}
}
自定义View引用的布局
<?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:layout_height="match_parent">
<ImageView
android:id="@+id/layout_img_jia"
android:layout_width="40dp"
android:src="@drawable/jia"
android:layout_gravity="center_vertical"
android:layout_height="40dp" />
<TextView
android:id="@+id/layout_All_Content"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="40dp" />
<ImageView
android:id="@+id/layout_img_jian"
android:src="@drawable/jian"
android:layout_width="40dp"
android:layout_gravity="center_vertical"
android:layout_height="40dp" />
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ExpandableListView
android:layout_above="@+id/asd"
android:id="@+id/main_expandale_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/asd"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/main_check_allCheck"
android:layout_weight="1"
android:text="全选"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/main_text_allContent"
android:text="总数量:0"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/main_text_allPrice"
android:layout_weight="1"
android:text="总价格:0"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
item_group.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:layout_height="match_parent">
<!--这里有一点这里面这哥CheckBox会抢焦点,导致无法点击条目-->
<!--解决方法加这个属性android:focusable="false"-->
<CheckBox
android:id="@+id/item_group_check"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/item_group_name"
android:textSize="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
item_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:orientation="horizontal"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/item_child_check"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/item_child_img"
android:layout_width="100dp"
android:layout_height="100dp" />
<LinearLayout
android:orientation="vertical"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/item_child_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/item_child_price"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<demo.bwie.com.shopping_trolley_demo.zdy_NumContent
android:id="@+id/item_child_content"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>