這篇博文詳細描述了從零開始實現購物車,使用的控件很簡單,就一個ExpandableListView,避免了嵌套,操作更簡單方便。
先看看效果吧。
怎麼樣,很棒吧,如圖所示,主要有店鋪名稱,商品價格,數量,圖片,底部有總價格和結算(刪除)按鈕。
1.那我們先把常用的控件添加依賴,這裏主要就是用一個第三方的刷新控件smartRefreshLayout。
刷新控件:com.scwang.smartrefresh:SmartRefreshLayout:1.0.5.1
2.現在就可以畫主界面了。主界面東西不多,主要就是一個刷新控件smartRefreshLayout,一個列表控件ExpandableListView,還有若干TextView,畫完大概就是這樣的(中間空白是因爲是列表還沒有數據)。
activity_main.xml代碼如下
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="京西不自營"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/bg_edit"
android:text="編輯"
android:textColor="#f0584f"
android:textSize="16sp" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#000" />
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/main_smartRefreshLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ExpandableListView
android:id="@+id/main_expandableListView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:text="總價格:0"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="結算"
android:textColor="#fff"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
值得一提的是,我們這裏給 "編輯" 按鈕添加了一個紅線背景,這裏我們手動畫一個xml背景文件即可。
bg_edit.xml代碼如下
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 邊角弧度 -->
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<!-- 包裹線條 -->
<stroke
android:width="1dp"
android:color="#f0584f" />
<!-- 內間距 -->
<padding
android:bottom="5dp"
android:left="10dp"
android:right="10dp"
android:top="5dp" />
</shape>
3.接下來我們就可以畫列表item了。
我們發現主要是以選中狀態、商品名稱、規格描述、價格、右邊的數量選擇器來顯示,這個不難,畫完大概就是這樣的
這裏稍微有點難度的是選擇器的繪製,主要是三個Textview,三者不同之處在於背景顏色和邊框顏色,我們先畫兩個背景xml
A、加減號所需的灰色背景xml:
bg_calculator_gray.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#f2f2f2" />
<stroke
android:width="1px"
android:color="#CCCCCC" />
</shape>
B、中間數字所需的白色背景xml:
bg_calculator_white.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ffffff"/>
<stroke android:color="#CCCCCC"
android:width="1px"/>
</shape>
現在沒什麼難度了,都懟上去吧,下面是子item佈局的詳細代碼(一個相對佈局就能搞定的就不要重複嵌套其它佈局了):
item_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:paddingRight="10dp">
<RelativeLayout
android:id="@+id/item_check"
android:layout_width="40dp"
android:layout_height="match_parent">
<ImageView
android:id="@+id/item_checkStatus"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerInParent="true"
android:src="@drawable/radio_choose" />
</RelativeLayout>
<ImageView
android:id="@+id/item_pic"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/item_check"
android:src="@color/colorPrimaryDark" />
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/item_pic"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/item_pic"
android:text="這是一隻標題"
android:textSize="16sp" />
<TextView
android:id="@+id/item_spec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/item_name"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/item_pic"
android:text="這是一隻規格" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/item_pic"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/item_pic"
android:text="¥0.00"
android:textColor="#f0584f" />
<TextView
android:id="@+id/item_reduce"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@id/item_pic"
android:layout_toLeftOf="@id/item_num"
android:background="@drawable/bg_calculator_gray"
android:gravity="center"
android:text="—" />
<TextView
android:id="@+id/item_num"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@id/item_pic"
android:layout_toLeftOf="@id/item_add"
android:background="@drawable/bg_calculator_white"
android:gravity="center"
android:text="0" />
<TextView
android:id="@+id/item_add"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@id/item_pic"
android:layout_alignParentRight="true"
android:background="@drawable/bg_calculator_gray"
android:gravity="center"
android:text="+" />
</RelativeLayout>
4.我們現在來繪製父item的佈局。
就一個選擇狀態圖片,店鋪名稱,很簡單,畫完大概就是這樣的
代碼如下:
item_main_head.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/item_head_check"
android:layout_width="40dp"
android:layout_height="40dp">
<ImageView
android:id="@+id/item_head_checkStatus"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerInParent="true"
android:src="@drawable/radio_choose" />
</RelativeLayout>
<TextView
android:id="@+id/item_head_shopName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="天貓一號賣家"
android:textSize="16sp" />
</LinearLayout>
5.現在我們搞一下店鋪和商品的列表bean。
店鋪主要是一個選中狀態isSelect和店鋪名shopNum。
商品主要是一個選中狀態isSelect、一個圖片goodsPic、一個標題goodsName、一個規格goodsSpec、一個原價格goodsOriginalPrice、一個選中器商品數量goodsShopNum。
把參數懟進去搞起來!!!代碼如下
MainBean.java
package com.fantasychong.carttest0128;
import java.io.Serializable;
import java.util.List;
/**
* @author fantasychong
* @date 2019/1/29
*/
public class MainBean implements Serializable {
private boolean isSelect; //店鋪選中狀態
private String shopName; //店鋪名稱
private List<MainItemBean> cartItemBeanList; //商品list
@Override
public String toString() {
return "MainBean{" +
"isSelect=" + isSelect +
", shopName='" + shopName + '\'' +
", cartItemBeanList=" + cartItemBeanList +
'}';
}
public MainBean(boolean isSelect, String shopName, List<MainItemBean> cartItemBeanList) {
this.isSelect = isSelect;
this.shopName = shopName;
this.cartItemBeanList = cartItemBeanList;
}
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public List<MainItemBean> getCartItemBeanList() {
return cartItemBeanList;
}
public void setCartItemBeanList(List<MainItemBean> cartItemBeanList) {
this.cartItemBeanList = cartItemBeanList;
}
public static class MainItemBean implements Serializable {
private boolean isSelect; //商品選中狀態
private int goodsPic; //商品圖片
private String goodsName; //商品名稱
private String goodsSpec; //商品規格
private String goodsOriginalPrice; //商品價格
private String goodsNum; //商品數量
public MainItemBean(boolean isSelect, int goodsPic, String goodsName, String goodsSpec, String goodsOriginalPrice, String goodsNum) {
this.isSelect = isSelect;
this.goodsPic = goodsPic;
this.goodsName = goodsName;
this.goodsSpec = goodsSpec;
this.goodsOriginalPrice = goodsOriginalPrice;
this.goodsNum = goodsNum;
}
@Override
public String toString() {
return "CartItemBean{" +
"isSelect=" + isSelect +
", goodsPic=" + goodsPic +
", goodsName='" + goodsName + '\'' +
", goodsSpec='" + goodsSpec + '\'' +
", goodsOriginalPrice='" + goodsOriginalPrice + '\'' +
", goodsNum='" + goodsNum + '\'' +
'}';
}
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
public int getGoodsPic() {
return goodsPic;
}
public void setGoodsPic(int goodsPic) {
this.goodsPic = goodsPic;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public String getGoodsSpec() {
return goodsSpec;
}
public void setGoodsSpec(String goodsSpec) {
this.goodsSpec = goodsSpec;
}
public String getGoodsOriginalPrice() {
return goodsOriginalPrice;
}
public void setGoodsOriginalPrice(String goodsOriginalPrice) {
this.goodsOriginalPrice = goodsOriginalPrice;
}
public String getGoodsNum() {
return goodsNum;
}
public void setGoodsNum(String goodsNum) {
this.goodsNum = goodsNum;
}
}
}
6.接下來,我們就來搞最重要也是最核心的列表adapter了(前方高能預警)。
新建一個MainAdapter,繼承核心基類BaseExpandableListAdapter,生成10個方法,我們先來分析一下。
這裏我們定義兩個從MainActivity通過構造函數傳進來的父list和子list,對應的分別是mainBeanList和mainItemBeanList()。
1)getGroupCount()和getChildCount()
顧名思義,返回父item和子item的個數,比如在我們購物車裏,那就是返回相應的店鋪個數和對應商鋪下商品的個數。
@Override
public int getGroupCount() {
return mainBeanList.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return mainItemBeanList.size();
}
2)getGroup()和getChild()
意爲獲取某個位置下的某個對象,這個是固定模板的。
@Override
public Object getGroup(int groupPosition) {
return mainBeanList.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mainItemBeanList.get(groupPosition).get(childPosition);
}
3)getGroupId()和getChildId()
意爲獲取某個位置下的對象id,這個是固定模板的。
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
4)hasStableIds()
字面意思是是否持有穩定的id,不過我還沒太搞懂這個是幹嘛的。。。返回true就行。
@Override
public boolean hasStableIds() {
return true;
}
5)isChildSelectable()
返回true就是表示可以操作子item。
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
6)重點在於getGroupView()和getChildView(),父子item的界面繪製、邏輯調用都在此完成
getGroupView():
首先是常規的尋找控件,設置複用。
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder groupHolder= null;
if (convertView== null){
groupHolder= new GroupHolder();
convertView= LayoutInflater.from(context).inflate(R.layout.item_main_head, parent, false);
convertView.setTag(groupHolder);
}else {
groupHolder= (GroupHolder) convertView.getTag();
}
return convertView;
}
class GroupHolder{
RelativeLayout check; //選擇點擊框
ImageView checkStatus; //選擇狀態圖片
LinearLayout layout; //父item佈局
}
getChildView():
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder childHolder= null;
if (convertView== null){
childHolder= new ChildHolder();
convertView= LayoutInflater.from(context).inflate(R.layout.item_main, parent, false);
childHolder.check= convertView.findViewById(R.id.item_check);
childHolder.checkStatus= convertView.findViewById(R.id.item_checkStatus);
childHolder.goodsPic= convertView.findViewById(R.id.item_pic);
childHolder.goodsName= convertView.findViewById(R.id.item_name);
childHolder.goodsSpec= convertView.findViewById(R.id.item_spec);
childHolder.goodsOriginalPrice= convertView.findViewById(R.id.item_price);
childHolder.reduce= convertView.findViewById(R.id.item_reduce);
childHolder.num= convertView.findViewById(R.id.item_num);
childHolder.add= convertView.findViewById(R.id.item_add);
convertView.setTag(childHolder);
}else {
childHolder= (ChildHolder) convertView.getTag();
}
childHolder.checkStatus.setImageResource(mainItemBeanList.get(groupPosition).get(childPosition).isSelect()? R.drawable.radio_choose: R.drawable.radio_normal_black);
childHolder.goodsPic.setImageResource(mainItemBeanList.get(groupPosition).get(childPosition).getGoodsPic());
childHolder.goodsName.setText(mainItemBeanList.get(groupPosition).get(childPosition).getGoodsName());
childHolder.goodsSpec.setText(mainItemBeanList.get(groupPosition).get(childPosition).getGoodsSpec());
childHolder.goodsOriginalPrice.setText("¥"+ mainItemBeanList.get(groupPosition).get(childPosition).getGoodsOriginalPrice());
childHolder.num.setText(mainItemBeanList.get(groupPosition).get(childPosition).getGoodsNum());
return convertView;
}
class ChildHolder{
RelativeLayout check; //選擇點擊框
ImageView checkStatus; //選擇狀態圖片
ImageView goodsPic; //商品圖片
TextView goodsName; //商品名稱
TextView goodsSpec; //商品規格
TextView goodsOriginalPrice; //商品原價
TextView reduce; //加減器減號
TextView num; //加減器數量
TextView add; //加減器加號
}
7.新建一個MainActivity。
1)我們先配置控件。
/**
* 配置控件
*/
private void initViews() {
expandableListView = findViewById(R.id.main_expandableListView);
smartRefreshLayout = findViewById(R.id.main_smartRefreshLayout);
}
2)配置適配器
/**
* 配置適配器
*/
private void initAdapter() {
adapter = new MainAdapter(MainActivity.this, mainBeanList, itemList);
expandableListView.setAdapter(adapter);
}
3)最後配置數據
/**
* 配置數據
*/
private void initData() {
//商品測試數據
MainBean.MainItemBean mainItemBean = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "iPhoneXs Max", "銀色 8G+256G", "9989", "1");
MainBean.MainItemBean mainItemBean1 = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "華爲P20 Pro", "深空灰色 6G+128G", "5299", "1");
MainBean.MainItemBean mainItemBean2 = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "小米9", "中國紅 8G+128G", "4999", "2");
MainBean.MainItemBean mainItemBean3 = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "三星Galaxy S10+", "黑色 4G+64G", "9998", "1");
MainBean.MainItemBean mainItemBean4 = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "魅族16th+", "黑色 4G+64G", "2698", "1");
MainBean.MainItemBean mainItemBean5 = new MainBean.MainItemBean(false, R.mipmap.ic_launcher, "OPPO FINDX", "黑色 4G+64G", "2698", "1");
List<MainBean.MainItemBean> mainItemBeanList = new ArrayList<>();
mainItemBeanList.add(mainItemBean);
mainItemBeanList.add(mainItemBean1);
List<MainBean.MainItemBean> mainItemBeanList1 = new ArrayList<>();
mainItemBeanList1.add(mainItemBean2);
mainItemBeanList1.add(mainItemBean3);
List<MainBean.MainItemBean> mainItemBeanList2 = new ArrayList<>();
mainItemBeanList2.add(mainItemBean4);
mainItemBeanList2.add(mainItemBean5);
//店鋪測試數據
MainBean mainBean = new MainBean(false, "天貓金牌賣家一號", mainItemBeanList);
MainBean mainBean1 = new MainBean(false, "地汪銀牌賣家二號", mainItemBeanList);
MainBean mainBean2 = new MainBean(false, "京西銅牌賣家三號", mainItemBeanList);
//添加店鋪列表
adapter.getMainList().clear();
adapter.getMainList().add(mainBean);
adapter.getMainList().add(mainBean1);
adapter.getMainList().add(mainBean2);
//添加商品佈局
adapter.getMainItemList().clear();
adapter.getMainItemList().add(mainItemBeanList);
adapter.getMainItemList().add(mainItemBeanList1);
adapter.getMainItemList().add(mainItemBeanList2);
adapter.notifyDataSetChanged();
//設置所有的子item都展開
for (int i = 0; i < adapter.getMainList().size(); i++) {
expandableListView.expandGroup(i);
}
}
8.現在我們就可以把項目跑起來了,看看效果。
納尼?商品呢?
差點蒙圈了,這是ExpandableListView,默認是收縮的,需要點開才能看到子佈局
那麼問題來了。。。。
我們不可能讓用戶每次都逐條去點,這樣會造成糟糕的用戶體驗,而且父item佈局默認還有一個箭頭影響觀感,所以我們要做一些簡單的處理。
1)首先讓所有的子item都默認打開。
打開MainActivity, 在配置數據的方法initData()裏。
//設置所有的子item都展開
for (int i= 0 ;i< mainBeanList.size(); i++){
expandableListView.expandGroup(i);
}
2)進入配置控件initViews()的方法裏, 再取消父item的默認箭頭
//去除父item的箭頭
expandableListView.setGroupIndicator(null);
3)最後,我們取消父item的點擊事件,避免誤觸後又摺疊起來。
打開adapter,在getGroupView()裏。
//取消父item的點擊事件
groupHolder.layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//什麼處理都不做
}
});
現在再跑起來~~~
牛逼啊馬飛,大致雛形已經出來了,下來我們就慢慢搞內部邏輯了。
9.接下來,就先搞這個父item的選中吧
根據邏輯,當我們選中父item時,會改變當前店鋪的選中狀態,當爲選中狀態時,同樣會選中當前店鋪下的所有商品,反之則會取消選中當前店鋪下的所有商品,同時也會改變總價格的計算狀態。。。。哇暈菜了,我們慢慢一步步來~
1)先搞定點擊改變父item也就是店鋪的選中狀態。
進入adapter的getGroupView()方法,設置點擊監聽。
//店鋪的選中監聽
groupHolder.check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mainBeanList.get(groupPosition).setSelect(!mainBeanList.get(groupPosition).isSelect());
notifyDataSetChanged();
}
});
這段代碼的意思就是,改變當前的select值爲相反值,然後刷新adapter。
看看效果:
點擊前:
點擊後:
再點擊:
完美!!!
2)下一步,我們來關聯點擊店鋪後順帶選擇對應下的商品列表。
for (int i = 0; i < mainItemBeanList.get(groupPosition).size(); i++) {
mainItemBeanList.get(groupPosition).get(i).setSelect(mainBean.isSelect());
}
現在跑起來,點選某個店鋪。
成功!!!
10.搞完店鋪的點選,接下來我們就搞商品的點選了
先設置選中監聽事件。
childHolder.check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainBean.MainItemBean mainItemBean= mainItemBeanList.get(groupPosition).get(childPosition);
mainItemBean.setSelect(!mainItemBean.isSelect());
notifyDataSetChanged();
}
});
同樣,當我們點選了某個店鋪下全部的商品,則把店鋪也自動點選,反之店鋪則不點選。
//當點選某個店鋪下全部商品時,則選中該店鋪
boolean noSelect= false;
for (int i= 0; i< mainItemBeanList.get(groupPosition).size(); i++){
if (!mainItemBeanList.get(groupPosition).get(i).isSelect()){
noSelect= true;
}
}
mainBeanList.get(groupPosition).setSelect(!noSelect);
運行看下效果:
11.接下來,我們做下加減器。
這裏的原理就是,點擊商品相應的加減號,進行數量的增減。這裏我們只需要把當前的商品數量引入計算即可。
//加減器加號
final ChildHolder finalChildHolder = childHolder;
childHolder.add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainBean.MainItemBean mainItemBean = mainItemBeanList.get(groupPosition).get(childPosition);
if (Integer.valueOf(mainItemBean.getGoodsNum()) < 5) {
mainItemBean.setGoodsNum(Integer.valueOf(finalChildHolder.num.getText().toString()) + 1 + "");
notifyDataSetChanged();
}
}
});
//加減器減號
childHolder.reduce.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainBean.MainItemBean mainItemBean = mainItemBeanList.get(groupPosition).get(childPosition);
if (Integer.valueOf(mainItemBean.getGoodsNum()) > 0) {
mainItemBean.setGoodsNum(Integer.valueOf(finalChildHolder.num.getText().toString()) - 1 + "");
notifyDataSetChanged();
}
}
});
這時我們要跟數量做一個限制,避免出現負數的現象,也可以做個最大數量限制,比如5。當商品數量達到極限值時,相應的按鈕變爲灰色並且不可點擊。
//加減器的極限值顯示狀態(達到最小值)
if ("0".equals(childHolder.num.getText().toString())) {
childHolder.reduce.setTextColor(context.getResources().getColor(R.color.color_a1a1a1));
} else {
childHolder.reduce.setTextColor(context.getResources().getColor(R.color.color_000000));
}
//加減器的極限值顯示狀態(達到最大值)
if ("5".equals(childHolder.num.getText().toString())) {
childHolder.add.setTextColor(context.getResources().getColor(R.color.color_a1a1a1));
} else {
childHolder.add.setTextColor(context.getResources().getColor(R.color.color_000000));
}
跑起來看看~
12.現在我們可以做一下價格計算了
首先是點選商品時的價格計算,因爲價格這裏涉及到精密計算,傳統的int float等計算起來不是那麼精密,所以我們這裏要引入BigDecimal,這是專門用來進行精密計算的類。
寫一個計算已勾選商品的價格計算的方法。
/**
* 計算商品價格
*/
public String getAllPrice(List<MainBean> list){
BigDecimal decimal= new BigDecimal("0");
if (list!= null){
for (int i= 0; i< list.size(); i++){
for (int j= 0; j< mainItemBeanList.get(i).size(); j++){
if (mainItemBeanList.get(i).get(j).isSelect()){
BigDecimal decimalGoodsNum= new BigDecimal(mainItemBeanList.get(i).get(j).getGoodsNum());
BigDecimal decimalGoodsPrice= new BigDecimal(mainItemBeanList.get(i).get(j).getGoodsOriginalPrice());
//將單價和數量相乘,累加
decimal= decimal.add(decimalGoodsNum.multiply(decimalGoodsPrice));
}
}
}
}
return decimal.toString();
}
現在我們先通過點選多個商品來進行價格計算。
Log.d("fantasychong_aaa", getAllPrice(mainBeanList));
9989+5299=15288
9989+5299+4999=20287
沒錯吧,這時我們取消一個選中
此時價格已更改爲15288,沒錯吧。
取消全部的選中,價格歸爲0。
完美啦,現在我們再把價格計算的方法添加到店鋪點選上,並把最終計算的價格呈現在底部價格欄。
這裏我們使用EventBus來實時刷新價格。
1)首先在gradle裏添加依賴。
//EventBus
implementation 'org.simple:androideventbus:1.0.5.1'
2)配置環境
在MainAdapter裏註冊
public MainAdapter(List<MainBean> mainBeanList, List<List<MainBean.MainItemBean>> mainItemBeanList, Context context) {
this.mainBeanList = mainBeanList;
this.mainItemBeanList = mainItemBeanList;
this.context = context;
//註冊EventBus
EventBus.getDefault().register(context);
}
在adapter裏取消註冊
這裏我們添加一個onDestroy()方法,最後在宿主Activity的onDestroy()方法裏執行即可。
public void onDestory(){
//EventBus取消註冊
EventBus.getDefault().unregister(context);
}
同樣在宿主MainActivity裏完成註冊與取消註冊。
/**
* 配置控件
*/
private void initViews() {
.....
//EventBus註冊
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
.....
//EventBus取消註冊
EventBus.getDefault().unregister(this);
}
3)配置完環境,我們打開adapter,在價格計算的入口發送實時價格。
分析下入口,共有4處分別爲
1.點選店鋪
2.點選商品
3.加減器加號
4.加減器減號
分別在入口通過EventBus發送價格。
//更改商品價格
EventBus.getDefault().post(getAllPrice(mainBeanList), TAG_REFRESH_PRICE);
4)打開宿主MainActivity,編寫接收方法並顯示價格。
/**
* 更改價格
* @param price
*/
@Subscriber(tag = TAG_REFRESH_PRICE, mode = ThreadMode.MAIN)
public void onRefreshPrice(String price){
priceTv.setText("總價格:"+ price);
}
現在跑起來,我們看下效果:
成功!
13.同時我們再顯示一下所選商品的數量
寫一個計算數量的方法getAllNum()。
/**
* 計算商品數量
*/
public String getAllNum(List<MainBean> list){
selectList= new ArrayList<>();
int allNum= 0;
if (list!= null){
for (int i= 0; i< list.size(); i++){
for (int j= 0; j< mainItemBeanList.get(i).size(); j++){
if (mainItemBeanList.get(i).get(j).isSelect()){
int num= 1* Integer.valueOf(mainItemBeanList.get(i).get(j).getGoodsNum());
allNum= allNum+ num;
}
}
}
}
return String.valueOf(allNum);
}
在店鋪點選,商品點選,加減器加減處添加方法。
//更改所選商品數量
EventBus.getDefault().post(getAllNum(mainBeanList), TAG_REFRESH_NUM);
在宿主MainActivity裏添加顯示方法。
/**
* 更改數量
*/
@Subscriber(tag = TAG_REFRESH_NUM, mode = ThreadMode.MAIN)
public void onRefreshNum(String num){
submitTv.setText("結算("+ num+ ")");
}
跑起來,看看效果:
成功!!!
14.現在我們做一下商品的刪除處理。
要想刪除,必須點擊右上角的編輯按鈕,下方結算按鈕會隨之顯示 “刪除”,點擊即可刪除。
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.main_edit:
if ("結算".equals(submitTv.getText().toString())){
submitTv.setText("刪除");
edit.setText("完成");
}else{
submitTv.setText("結算");
edit.setText("編輯");
}
break;
default:
break;
}
}
當顯示”刪除“時,編寫對應的方法。
/**
* 刪除所選商品
*/
public void removeGoods() {
for (int i = 0; i < mainBeanList.size(); i++) {
if (mainBeanList.get(i).isSelect()) {
mainBeanList.remove(i);
mainItemBeanList.remove(i);
} else {
for (int j = 0; j < mainItemBeanList.get(i).size(); j++) {
if (mainItemBeanList.get(i).get(j).isSelect()) {
mainItemBeanList.get(i).remove(j);
}
}
}
}
notifyDataSetChanged();
}
這段代碼意思是,當選中店鋪(選中了該店鋪下的所有商品)時,清除掉對應的店鋪和商品list,別忘了最後notifyDataSetChanged()
運行看下效果:
選中一個商品、刪除。
選中一個店鋪,刪除。
同時清除底部的價格和數量
//更改商品價格
EventBus.getDefault().post(getAllPrice(mainBeanList), TAG_REFRESH_PRICE);
//更改所選商品數量
EventBus.getDefault().post(getAllNum(mainBeanList), TAG_REFRESH_NUM);
完美!
15.現在我們做一下結算功能
結算的思路就是把已選中的商品放置在一個集合中,之後根據需求對該集合進行相應的處理。
在adapter裏寫一個獲取選中商品list的方法。
/**
* 獲取所選商品
*/
public List<MainBean.MainItemBean> getSelectList(){
selectList= new ArrayList<>();
for (int i= 0; i< mainBeanList.size(); i++){
for (int j= 0; j< mainItemBeanList.get(i).size(); j++){
if (mainItemBeanList.get(i).get(j).isSelect()){
selectList.add(mainItemBeanList.get(i).get(j));
}
}
}
return selectList;
}
在結算入口打印日誌
if ("結算".equals(submitTv.getText().toString())){
Log.d("fantasychong_selctList", adapter.getSelectList().toString());
}
運行,看效果:
這樣就對應上了。
16.現在我們已經把基本功能全都完成了,最後做下下拉刷新處理。
首先實現下拉刷新監聽請求數據。
//下拉刷新監聽
smartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshLayout) {
initData();
}
});
這時,當我們選擇了某些商品後,下拉刷新結果發現
納尼?選中的商品怎麼又不選中了?
所以,我們這裏要做下選中狀態的保存。
這裏我們需要給每個商品做一個唯一標識符id,打開MainItemBean,添加id參數。
private String id; //商品id
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
同時構造函數也添加上該參數
這時在請求新數據initData()方法中,在添加數據之前,先把舊數據的商品選中狀態保存到新數據中。
//保存選中狀態
List<SelectBean> selectBeanList = new ArrayList<>();
if (adapter.getMainItemList().size() != 0 && adapter.getMainItemList() != null) {
for (int i = 0; i < adapter.getMainList().size(); i++) {
for (int j = 0; j < adapter.getMainItemList().get(i).size(); j++) {
if (adapter.getMainItemList().get(i).get(j).isSelect()) {
selectBean = new SelectBean(adapter.getMainItemList().get(i).get(j).getId(), adapter.getMainItemList().get(i).get(j).isSelect());
selectBeanList.add(selectBean);
}
}
}
for (int i = 0; i < mainItemBeanList.size(); i++) {
for (int j = 0; j < selectBeanList.size(); j++) {
if (selectBeanList.get(j).getId().equals(mainItemBeanList.get(i).getId())) {
mainItemBeanList.get(i).setSelect(selectBeanList.get(j).isSelect());
}
}
}
}
這時把保存的商品選中狀態賦給新數據。
//將保存的選中狀態賦給新請求到的數據
if (adapter.getMainItemList().size() != 0 && adapter.getMainItemList() != null) {
for (int i = 0; i < adapter.getMainList().size(); i++) {
for (int j = 0; j < adapter.getMainItemList().get(i).size(); j++) {
if (adapter.getMainItemList().get(i).get(j).isSelect()) {
selectBean = new SelectBean(adapter.getMainItemList().get(i).get(j).getId(), adapter.getMainItemList().get(i).get(j).isSelect());
selectBeanList.add(selectBean);
}
}
}
for (int i = 0; i < mainItemBeanList.size(); i++) {
for (int j = 0; j < selectBeanList.size(); j++) {
if (selectBeanList.get(j).getId().equals(mainItemBeanList.get(i).getId())) {
mainItemBeanList.get(i).setSelect(selectBeanList.get(j).isSelect());
}
}
}
for (int i = 0; i < mainItemBeanList.size(); i++) {
for (int j = 0; j < selectBeanList.size(); j++) {
if (selectBeanList.get(j).getId().equals(mainItemBeanList1.get(i).getId())) {
mainItemBeanList1.get(i).setSelect(selectBeanList.get(j).isSelect());
}
}
}
for (int i = 0; i < mainItemBeanList.size(); i++) {
for (int j = 0; j < selectBeanList.size(); j++) {
if (selectBeanList.get(j).getId().equals(mainItemBeanList2.get(i).getId())) {
mainItemBeanList2.get(i).setSelect(selectBeanList.get(j).isSelect());
}
}
}
}
最後根據商品的選中狀態來決定對應店鋪的選中狀態。
//根據子item的選中狀態來決定店鋪的點選狀態
boolean noSelect = false;
for (int j = 0; j < adapter.getMainItemList().get(0).size(); j++) {
if (!adapter.getMainItemList().get(0).get(j).isSelect()) {
noSelect = true;
}
adapter.getMainList().get(0).setSelect(!noSelect);
}
boolean noSelect1 = false;
for (int j = 0; j < adapter.getMainItemList().get(1).size(); j++) {
if (!adapter.getMainItemList().get(1).get(j).isSelect()) {
noSelect1 = true;
}
adapter.getMainList().get(1).setSelect(!noSelect1);
}
boolean noSelect2 = false;
for (int j = 0; j < adapter.getMainItemList().get(2).size(); j++) {
if (!adapter.getMainItemList().get(2).get(j).isSelect()) {
noSelect2 = true;
}
adapter.getMainList().get(2).setSelect(!noSelect2);
}
最後別忘了通知adapter刷新。
adapter.notifyDataSetChanged();
至此全部完成,沒有demo的博客不是好博客,鏈接附上!