##### foreword Actually do shopping cart of an electric business, return true not an easy live. But as long as you get the idea, step by step, you’ll find that’s it. Waste not to say, direct effect diagram complete code, github link, hope to give a star, thank you


# # # # # 2


##### main idea of the whole layout is ExpandableListView, and then define a custom ActionBar, ActionBar above the display of shopping cart number, through the ActionBar above the editing state, store layout, all goods layout, the bottom layout should be changed accordingly, In the edit state, you need to change the quantity of goods, delete goods, select all goods, and hide the edit of the shop. Non-edit state can display the store’s edit, display settlement, commodity information. Through the editing status above each store, the layout of all goods under the store should be changed accordingly. In edit state, you need to change the quantity of goods and delete goods. In the unedited state, only the product information needs to be displayed. When all commodities under the store are checked, the corresponding store should also be checked. On the contrary, as long as there is a commodity under the shop is not ticked, then the shop does not need to tick. In fact, logic is quite simple, complex logic is actually composed of a lot of simple logic, we just need to simplify the complex logic into a lot of simple logic, we can complete a general idea


##### code teaching


Our first step is to customize an ActionBar, which can be solved in a few lines of code.

Private void initActionBar() {// Hide title bar if (getActionBar ()! = null) {// Drop shadows getSupportActionBar().setelevation (0); getSupportActionBar().setDisplayShowTitleEnabled(false); getSupportActionBar().setDisplayShowCustomEnabled(true); View view = getLayoutInflater().inflate(R.layout.acitonbar, null); findView(view); getSupportActionBar().setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); ActionBar.LayoutParams lp = (ActionBar.LayoutParams) view.getLayoutParams(); lp.gravity = Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.CENTER_HORIZONTAL; getSupportActionBar().setCustomView(view, lp); }Copy the code

The effect picture after completion:


The second step is to write the entire layout XML file, the basic knowledge is not much to say.

    
    
    
    
    
    
    
        
        
            
                
                    
                    
                
                
            
            
            
        
            
            
            
        
        
    
        

    

The effect picture after completion:


Step 4 focuses on the code

  • ActionBar edit button processing
case R.id.actionBar_edit: flag = ! flag; setActionBarEditor(); setVisiable(); break;
private void setActionBarEditor() { for (int i = 0; i < groups.size(); i++) { StoreInfo group = groups.get(i); if (group.isActionBarEditor()) { group.setActionBarEditor(false); } else { group.setActionBarEditor(true); } } adapter.notifyDataSetChanged(); } private void setVisiable() { if (flag) { orderInfo.setVisibility(View.GONE); shareInfo.setVisibility(View.VISIBLE); ActionBarEdit. SetText (" finished "); } else { orderInfo.setVisibility(View.VISIBLE); shareInfo.setVisibility(View.GONE); ActionBarEdit. SetText (" edit "); }}
  • The callback interface

CheckBox multiple selection, check the store, check the callback of goods

    public interface CheckInterface {
       
        void checkGroup(int groupPosition, boolean isChecked);
        void checkChild(int groupPosition, int childPosition, boolean isChecked);
    }

By monitoring the checkBox check state, easy to calculate the amount of goods and delete goods, calculate the number of shopping carts and other operations.


The store corresponds to the number of goods increase, decrease, delete, update callback

public interface ModifyCountInterface {
        void doIncrease(int groupPosition, int childPosition, View showCountView, boolean isChecked);
        void doDecrease(int groupPosition, int childPosition, View showCountView, boolean isChecked);
        void doUpdate(int groupPosition,int childPosition,View showCountView, boolean isChecked);
        void childDelete(int groupPosition, int childPosition);
    }

Through the change of the number of goods under the shop, to calculate the amount and the number of shopping carts, when the goods of the shop are deleted, the shop will be deleted from the shopping cart.

  • Related shopping cart operations

Increase the quantity of goods

 @Override
    public void doIncrease(int groupPosition, int childPosition, View showCountView, boolean isChecked) {
        GoodsInfo good = (GoodsInfo) adapter.getChild(groupPosition, childPosition);
        int count = good.getCount();
        count++;
        good.setCount(count);
        ((TextView) showCountView).setText(String.valueOf(count));
        adapter.notifyDataSetChanged();
        calulate();
    }

Reduce the quantity of goods

 @Override
    public void doDecrease(int groupPosition, int childPosition, View showCountView, boolean isChecked) {
        GoodsInfo good = (GoodsInfo) adapter.getChild(groupPosition, childPosition);
        int count = good.getCount();
        if (count == 1) {
            return;
        }
        count--;
        good.setCount(count);
        ((TextView) showCountView).setText("" + count);
        adapter.notifyDataSetChanged();
        calulate();
    }

Delete the goods

@Override
    public void childDelete(int groupPosition, int childPosition) {
        StoreInfo group = groups.get(groupPosition);
        List child = childs.get(group.getId());
        child.remove(childPosition);
        if (child.size() == 0) {
            groups.remove(groupPosition);
        }
        adapter.notifyDataSetChanged();
        calulate();
    }

Update quantity of goods

public void doUpdate(int groupPosition, int childPosition, View showCountView, boolean isChecked) { GoodsInfo good = (GoodsInfo) adapter.getChild(groupPosition, childPosition); int count = good.getCount(); Utilslog. I (" to update data, quantity "+ count + ""); ((TextView) showCountView).setText(String.valueOf(count)); adapter.notifyDataSetChanged(); calulate(); }

Check the store, goods

@Override public void checkChild(int groupPosition, int childPosition, boolean isChecked) { boolean allChildSameState = true; StoreInfo group = groups.get(groupPosition); StoreInfo group = groups.get(groupPosition); List child = childs.get(group.getId()); for (int i = 0; i < child.size(); If (child.get(I).ischoosed ()! = isChecked) { allChildSameState = false; break; } } if (allChildSameState) { group.setChoosed(isChecked); } else {group.setchoosed (false);} else {group.setchoosed (false); } if (isCheckAll()) {allcheckbox.setchecked (true); } else {allcheckbox.setchecked (false); / / unclick} adapter. NotifyDataSetChanged (); calulate(); } @Override public void checkGroup(int groupPosition, boolean isChecked) { StoreInfo group = groups.get(groupPosition); List child = childs.get(group.getId()); for (int i = 0; i < child.size(); i++) { child.get(i).setChoosed(isChecked); } if (isCheckAll()) { allCheckBox.setChecked(true); } else {allcheckbox.setchecked (false); / / unclick} adapter. NotifyDataSetChanged (); calulate(); }

The traversal at the bottom deletes the item

Delete operation 1. Do not delete the array while traversing. Private void doDelete() {List toBeDeleteGroups = new ArrayList(); private void doDelete() {List toBeDeleteGroups = new ArrayList(); For (int I = 0; i < groups.size(); i++) { StoreInfo group = groups.get(i); if (group.isChoosed()) { toBeDeleteGroups.add(group); } List toBeDeleteChilds = new ArrayList(); List child = childs.get(group.getid ()); for (int j = 0; j < child.size(); j++) { if (child.get(j).isChoosed()) { toBeDeleteChilds.add(child.get(j)); } } child.removeAll(toBeDeleteChilds); } groups.removeAll(toBeDeleteGroups); // reset the shopping cart setCartNum(); adapter.notifyDataSetChanged(); }

All selection and anti-selection at the bottom

private boolean isCheckAll() { for (StoreInfo group : groups) { if (! group.isChoosed()) { return false; } } return true; } private void doCheckAll() { for (int i = 0; i < groups.size(); i++) { StoreInfo group = groups.get(i); group.setChoosed(allCheckBox.isChecked()); List child = childs.get(group.getId()); for (int j = 0; j < child.size(); j++) { child.get(j).setChoosed(allCheckBox.isChecked()); / / here appear mistakes}} adapter. The notifyDataSetChanged (); calulate(); }

Calculate commodity price

Private void calulate() {mtotalPrice = 0.00; mtotalCount = 0; for (int i = 0; i < groups.size(); i++) { StoreInfo group = groups.get(i); List child = childs.get(group.getId()); for (int j = 0; j < child.size(); j++) { GoodsInfo good = child.get(j); if (good.isChoosed()) { mtotalCount++; mtotalPrice += good.getPrice() * good.getCount(); }} totalPrice. SetText ("¥" + mtotalPrice ""); Gopay. setText(" to pay (" + mtotalCount + ")"); if (mtotalCount == 0) { setCartNum(); } else {shoppingcatNum. SetText (" shopping cart (" + mtotalCount + ")"); }}

Set the number of carts and empty the cart

private void setCartNum() { int count = 0; for (int i = 0; i < groups.size(); i++) { StoreInfo group = groups.get(i); group.setChoosed(allCheckBox.isChecked()); List Childs = childs.get(group.getId()); for (GoodsInfo childs : Childs) { count++; If (count == 0) {clearCart(); } else {shoppingcatNum. SetText (" shopping cart (" + count + ")"); }} private void clearCart() {shoppingcatNum. SetText (" 0 "); actionBarEdit.setVisibility(View.GONE); llCart.setVisibility(View.GONE); empty_shopcart.setVisibility(View.VISIBLE); // There is an error}

Initialize store and product information

* Analog data

Following the adapter's data list populating principle, the group element is placed in a list, and the corresponding child element is placed in the Map, whose Key is the Id of the group element. Private void initData() {McOntext = this; groups = new ArrayList(); childs = new HashMap>(); for (int i = 0; i < 5; I++) {groups. The add (new StoreInfo (I + ""," the first pony "+ (I + 1) + number" pawn ")); List goods = new ArrayList<>(); for (int j = 0; j <= i; j++) { int[] img = {R.drawable.cmaz, R.drawable.cmaz, R.drawable.cmaz, R.drawable.cmaz, R.drawable.cmaz, R.drawable.cmaz}; //i-j is the id of the item, which corresponds to the number of the item in the store. Add (new GoodsInfo(I + "-" + j, "merchandise ", groups.get(I).getName() +" + (j + 1) + ", 255.00 + new Random().nextint (1500), 1555 + new Random().nextint (3000), "第一 个 ", "第一 个 ", img[j], new Random().nextInt(100))); } childs.put(groups.get(i).getId(), goods); }}

  • Shopping cart adapter without further details, just post the code. That’s a lot of code
public class ShopcatAdapter extends BaseExpandableListAdapter {
    private List groups;
    //这个String对应着StoreInfo的Id,也就是店铺的Id
    private Map> childrens;
    private Context mcontext;
    private CheckInterface checkInterface;
    private ModifyCountInterface modifyCountInterface;
    private GroupEditorListener groupEditorListener;
    private int count = 0;
    private boolean flag=true; //组的编辑按钮是否可见,true可见,false不可见


    public ShopcatAdapter(List groups, Map> childrens, Context mcontext) {
        this.groups = groups;
        this.childrens = childrens;
        this.mcontext = mcontext;
    }

    @Override
    public int getGroupCount() {
        return groups.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        String groupId = groups.get(groupPosition).getId();
        return childrens.get(groupId).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return groups.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        List childs = childrens.get(groups.get(groupPosition).getId());
        return childs.get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        final GroupViewHolder groupViewHolder;
        if (convertView == null) {
            convertView = View.inflate(mcontext, R.layout.item_shopcat_group, null);
            groupViewHolder = new GroupViewHolder(convertView);
            convertView.setTag(groupViewHolder);
        } else {
            groupViewHolder = (GroupViewHolder) convertView.getTag();
        }
        final StoreInfo group = (StoreInfo) getGroup(groupPosition);
        groupViewHolder.storeName.setText(group.getName());
        groupViewHolder.storeCheckBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                group.setChoosed(((CheckBox) v).isChecked());
                checkInterface.checkGroup(groupPosition, ((CheckBox) v).isChecked());
            }
        });
        groupViewHolder.storeCheckBox.setChecked(group.isChoosed());

        /**【文字指的是组的按钮的文字】
         * 当我们按下ActionBar的 "编辑"按钮, 应该把所有组的文字显示"编辑",并且设置按钮为不可见
         * 当我们完成编辑后,再把组的编辑按钮设置为可见
         * 不懂,请自己操作淘宝,观察一遍
         */
        if(group.isActionBarEditor()){
            group.setEditor(false);
            groupViewHolder.storeEdit.setVisibility(View.GONE);
            flag=false;
        }else{
            flag=true;
            groupViewHolder.storeEdit.setVisibility(View.VISIBLE);
        }

        /**
         * 思路:当我们按下组的"编辑"按钮后,组处于编辑状态,文字显示"完成"
         * 当我们点击“完成”按钮后,文字显示"编辑“,组处于未编辑状态
         */
        if (group.isEditor()) {
            groupViewHolder.storeEdit.setText("完成");
        } else {
            groupViewHolder.storeEdit.setText("编辑");
        }

        groupViewHolder.storeEdit.setOnClickListener(new GroupViewClick(group, groupPosition, groupViewHolder.storeEdit));
        return convertView;
    }

    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        final ChildViewHolder childViewHolder;
        if (convertView == null) {
            convertView = View.inflate(mcontext, R.layout.item_shopcat_product, null);
            childViewHolder = new ChildViewHolder(convertView);
            convertView.setTag(childViewHolder);
        } else {
            childViewHolder = (ChildViewHolder) convertView.getTag();
        }

        /**
         * 根据组的编辑按钮的可见与不可见,去判断是组对下辖的子元素编辑  还是ActionBar对组的下瞎元素的编辑
         * 如果组的编辑按钮可见,那么肯定是组对自己下辖元素的编辑
         * 如果组的编辑按钮不可见,那么肯定是ActionBar对组下辖元素的编辑
         */
        if(flag){
            if (groups.get(groupPosition).isEditor()) {
                childViewHolder.editGoodsData.setVisibility(View.VISIBLE);
                childViewHolder.delGoods.setVisibility(View.VISIBLE);
                childViewHolder.goodsData.setVisibility(View.GONE);
            } else {
                childViewHolder.delGoods.setVisibility(View.VISIBLE);
                childViewHolder.goodsData.setVisibility(View.VISIBLE);
                childViewHolder.editGoodsData.setVisibility(View.GONE);
            }
        }else{

            if(groups.get(groupPosition).isActionBarEditor()){
                childViewHolder.delGoods.setVisibility(View.GONE);
                childViewHolder.editGoodsData.setVisibility(View.VISIBLE);
                childViewHolder.goodsData.setVisibility(View.GONE);
            }else{
                childViewHolder.delGoods.setVisibility(View.VISIBLE);
                childViewHolder.goodsData.setVisibility(View.VISIBLE);
                childViewHolder.editGoodsData.setVisibility(View.GONE);
            }
        }

        final GoodsInfo child = (GoodsInfo) getChild(groupPosition, childPosition);
        if (child != null) {
            childViewHolder.goodsName.setText(child.getDesc());
            childViewHolder.goodsPrice.setText("¥" + child.getPrice() + "");
            childViewHolder.goodsNum.setText(String.valueOf(child.getCount()));
            childViewHolder.goodsImage.setImageResource(R.drawable.cmaz);
            childViewHolder.goods_size.setText("门票:" + child.getColor() + ",类型:" + child.getSize());
            //设置打折前的原价
            SpannableString spannableString = new SpannableString("¥" + child.getPrime_price() + "");
            StrikethroughSpan span = new StrikethroughSpan();
            spannableString.setSpan(span,0,spannableString.length()-1+1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
            //避免无限次的append
            if (childViewHolder.goodsPrimePrice.length() > 0) {
                childViewHolder.goodsPrimePrice.setText("");
            }
            childViewHolder.goodsPrimePrice.setText(spannableString);
            childViewHolder.goodsBuyNum.setText("x" + child.getCount() + "");
            childViewHolder.singleCheckBox.setChecked(child.isChoosed());
            childViewHolder.singleCheckBox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    child.setChoosed(((CheckBox) v).isChecked());
                    childViewHolder.singleCheckBox.setChecked(((CheckBox) v).isChecked());
                    checkInterface.checkChild(groupPosition, childPosition, ((CheckBox) v).isChecked());
                }
            });
            childViewHolder.increaseGoodsNum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    modifyCountInterface.doIncrease(groupPosition, childPosition, childViewHolder.goodsNum, childViewHolder.singleCheckBox.isChecked());
                }
            });
            childViewHolder.reduceGoodsNum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    modifyCountInterface.doDecrease(groupPosition, childPosition, childViewHolder.goodsNum, childViewHolder.singleCheckBox.isChecked());
                }
            });
            childViewHolder.goodsNum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showDialog(groupPosition,childPosition,childViewHolder.goodsNum,childViewHolder.singleCheckBox.isChecked(),child);
                }
            });
            childViewHolder.delGoods.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new AlertDialog.Builder(mcontext)
                            .setMessage("确定要删除该商品吗")
                            .setNegativeButton("取消",null)
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    modifyCountInterface.childDelete(groupPosition,childPosition);
                                }
                            })
                            .create()
                            .show();;
                }
            });
        }
        return convertView;
    }
    private void showDialog(final int groupPosition, final int childPosition, final View showCountView,final  boolean isChecked, final  GoodsInfo child) {
        final AlertDialog.Builder alertDialog_Builder=new AlertDialog.Builder(mcontext);
        View view= LayoutInflater.from(mcontext).inflate(R.layout.dialog_change_num,null);
        final AlertDialog  dialog=alertDialog_Builder.create();
        dialog.setView(view);
        count=child.getCount();
        final EditText num= (EditText) view.findViewById(R.id.dialog_num);
        num.setText(count+"");
        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                UtilTool.showKeyboard(mcontext,showCountView);
            }
        });
        final TextView increase= (TextView) view.findViewById(R.id.dialog_increaseNum);
        final TextView DeIncrease=(TextView)view.findViewById(R.id.dialog_reduceNum);
        final TextView pButton= (TextView) view.findViewById(R.id.dialog_Pbutton);
        final TextView nButton= (TextView) view.findViewById(R.id.dialog_Nbutton);
        nButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        pButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int number=Integer.parseInt(num.getText().toString().trim());
                if(number==0){
                    dialog.dismiss();
                }else{
                    UtilsLog.i("数量="+number+"");
                    num.setText(String.valueOf(number));
                    child.setCount(number);
               modifyCountInterface.doUpdate(groupPosition,childPosition,showCountView,isChecked);
                 dialog.dismiss();
                }
            }
        });
        increase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                count++;
                num.setText(String.valueOf(count));
            }
        });
        DeIncrease.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(count>1){
                    count--;
                    num.setText(String.valueOf(count));
                }
            }
        });
        dialog.show();
    }
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }
    public GroupEditorListener getGroupEditorListener() {
        return groupEditorListener;
    }
    public void setGroupEditorListener(GroupEditorListener groupEditorListener) {
        this.groupEditorListener = groupEditorListener;
    }
    public CheckInterface getCheckInterface() {
        return checkInterface;
    }
    public void setCheckInterface(CheckInterface checkInterface) {
        this.checkInterface = checkInterface;
    }
    public ModifyCountInterface getModifyCountInterface() {
        return modifyCountInterface;
    }
    public void setModifyCountInterface(ModifyCountInterface modifyCountInterface) {
        this.modifyCountInterface = modifyCountInterface;
    }
    static class GroupViewHolder {
        @BindView(R.id.store_checkBox)
        CheckBox storeCheckBox;
        @BindView(R.id.store_name)
        TextView storeName;
        @BindView(R.id.store_edit)
        TextView storeEdit;

        public GroupViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
    public interface CheckInterface {
        void checkGroup(int groupPosition, boolean isChecked);
        void checkChild(int groupPosition, int childPosition, boolean isChecked);
    }
        void doIncrease(int groupPosition, int childPosition, View showCountView, boolean isChecked);

        void doDecrease(int groupPosition, int childPosition, View showCountView, boolean isChecked);

        void doUpdate(int groupPosition,int childPosition,View showCountView, boolean isChecked);
        void childDelete(int groupPosition, int childPosition);
    }
    public interface GroupEditorListener {
        void groupEditor(int groupPosition);
    }
    private class GroupViewClick implements View.OnClickListener {
        private StoreInfo group;
        private int groupPosition;
        private TextView editor;

        public GroupViewClick(StoreInfo group, int groupPosition, TextView editor) {
            this.group = group;
            this.groupPosition = groupPosition;
            this.editor = editor;
        }
        @Override
        public void onClick(View v) {
            if (editor.getId() == v.getId()) {
                groupEditorListener.groupEditor(groupPosition);
                if (group.isEditor()) {
                    group.setEditor(false);
                } else {
                    group.setEditor(true);
                }
                notifyDataSetChanged();
            }
        }
    }


    static class ChildViewHolder {
        @BindView(R.id.single_checkBox)
        CheckBox singleCheckBox;
        @BindView(R.id.goods_image)
        ImageView goodsImage;
        @BindView(R.id.goods_name)
        TextView goodsName;
        @BindView(R.id.goods_size)
        TextView goods_size;
        @BindView(R.id.goods_price)
        TextView goodsPrice;
        @BindView(R.id.goods_prime_price)
        TextView goodsPrimePrice;
        @BindView(R.id.goods_buyNum)
        TextView goodsBuyNum;
        @BindView(R.id.goods_data)
        RelativeLayout goodsData;
        @BindView(R.id.reduce_goodsNum)
        TextView reduceGoodsNum;
        @BindView(R.id.goods_Num)
        TextView goodsNum;
        @BindView(R.id.increase_goods_Num)
        TextView increaseGoodsNum;
        @BindView(R.id.goodsSize)
        TextView goodsSize;
        @BindView(R.id.del_goods)
        TextView delGoods;
        @BindView(R.id.edit_goods_data)
        LinearLayout editGoodsData;

        public ChildViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
}

##### summary in fact, the amount of code is still quite a lot, the main idea or. The idea is clear, naturally. Code according to play again, thinking naturally clear. The difficulty lies in the relationship between stores and commodities, single boxes, edit buttons and the change of layout.