原版程式碼請檢視這裡
前言
這個次為大家帶來的是一個完整的商品屬性篩選與商品篩選。什麼意思?都見過淘寶、京東等愛啪啪吧,裡面有個商品詳情,可以選擇商品的屬性,然後篩選出這個商品的具體型號,這樣應該知道了吧?不知道也沒關係,下面會有展示圖。
關於商品篩選是有兩種方式(至少我只見到兩種):
第一種: 將所有的商品的所有屬性及詳情返回給客戶端,由客戶端進行篩選。
淘寶用的就是這種。
第二種: 將所有的屬性返回給客戶端,客戶選擇完成屬性後將屬性傳送給後臺
,再由後臺根據屬性篩選出具體商品返回給客戶端。
京東就是這樣搞的。。複製程式碼
兩種方式各有各的好處:
第一種:體驗性特別好,使用者感覺不到延遲,立即選中立即就篩選出了詳情。就是客戶端比較費勁。。。
第二種:客戶端比較省時間,但是體驗性太差了,你想想,在網路不是很通暢的時候,你選擇一個商品還得等老半天。
因為當時我沒有參加到這個介面的設計,導致一直在變化。。我才不會告訴不是後臺不給力,篩選不出來才一股腦的將所有鍋甩給客戶端。
技術點
-
流式佈局
商品的屬性並不是一樣長的,所以需要自動適應內容的一個控制元件。 推薦hongyang的部落格。我就是照著那個搞的。複製程式碼
-
RxJava
不要問我,我不知道,我也是新手,我就是用它做出了效果,至於有沒有 用對,那我就不知道了。反正目的是達到了。複製程式碼
- Json解析???
準備
xml佈局
這個部分的佈局不是很難,只是程式碼量較多,我們們就省略吧,直接看效果吧
可以看到機身顏色、記憶體、版本下面都是空的,因為我們還沒有將屬性篩選出來。
資料分析
先看看整體的資料結構是怎麼樣的
每一個商品都有一個父類,僅作標識,不參與計算,比如資料中的華為P9就是一個商品的類目,在這下面有著各種屬性組成的商品子類,這才是真正的商品。
而一個詳細的商品是有三個基礎屬性所組成:
1. 版本
2. 記憶體
3. 制式複製程式碼
如上圖中一個具體的商品的名稱:”華為 P9全網通 3GB+32GB版 流光金 移動聯通電信4G手機 雙卡雙待”
所以,要獲得一個具體的商品是非常的簡單,只需要客戶選中的三個屬性與上圖中所對應的屬性完全相同,就能得到這個商品。其中最關鍵的還是將所有的商品屬性篩選出來。
篩選出所有屬性及圖片
本文中使用的資料是直接從Assets目錄中直接讀取的。
篩選出該商品的所有屬性,怎麼做呢?其實也是很簡單的,直接for所有商品的所有屬性,然後儲存起來,去除重複的屬性,那麼最後剩下的就是該商品的屬性了
/**
* 初始化商品資訊
* <li>1. 提取所有的屬性</li>
* <li>2. 提取所有顏色的照片</li>
*/
private void initGoodsInfo() {
//所有的顏色
mColors = new ArrayList<>();
//篩選過程中臨時存放顏色
mTempColors = new ArrayList<>();
//所有的記憶體
mMonerys = new ArrayList<>();
//篩選過程中臨時的記憶體
mTempMonerys = new ArrayList<>();
//所有的版本
mVersions = new ArrayList<>();
//篩選過程中的臨時版本
mTempVersions = new ArrayList<>();
//獲取到所有的商品
shopLists = responseDto.getMsg().getChilds();
callBack.refreshSuccess("¥" + responseDto.getPricemin() + " - " + responseDto.getPricemax(), responseDto.getMsg().getParent().getName());
callBack.parentName(responseDto.getMsg().getParent().getName());
//遍歷商品
Observable.from(shopLists)
//轉換物件 獲取所有商品的屬性集合
.flatMap(childsEntity -> Observable.from(childsEntity.getAttrinfo().getAttrs()))
.subscribe(attrsEntity -> {
//判斷顏色
if (mActivity.getString(R.string.shop_color).equals(attrsEntity.getAttrname()) && !mTempColors.contains(attrsEntity.getAttrvalue())) {
mColors.add(new TagInfo(attrsEntity.getAttrvalue()));
mTempColors.add(attrsEntity.getAttrvalue());
}
//判斷制式
if (mActivity.getString(R.string.shop_standard).equals(attrsEntity.getAttrname()) && !mTempVersions.contains(attrsEntity.getAttrvalue())) {
mVersions.add(new TagInfo(attrsEntity.getAttrvalue()));
mTempVersions.add(attrsEntity.getAttrvalue());
}
//判斷記憶體
if (mActivity.getString(R.string.shop_monery).equals(attrsEntity.getAttrname()) && !mTempMonerys.contains(attrsEntity.getAttrvalue())) {
mMonerys.add(new TagInfo(attrsEntity.getAttrvalue()));
mTempMonerys.add(attrsEntity.getAttrvalue());
}
});
// 提取出 每種顏色的照片
tempImageColor = new ArrayList<>();
mImages = new ArrayList<>();
//遍歷所有的商品列表
Observable.from(shopLists)
.subscribe(childsEntity -> {
String color = childsEntity.getAttrinfo().getAttrs().get(0).getAttrvalue();
if (!tempImageColor.contains(color)) {
mImages.add(childsEntity.getShowimg());
tempImageColor.add(color);
}
});
// 提取出 每種顏色的照片
//通知圖片
callBack.changeData(mImages, "¥" + responseDto.getPricemin() + " - " + responseDto.getPricemax());
callBack.complete(null);
}複製程式碼
初始化屬性列表
屬性之間是有一些關係的,比如我這裡是以顏色為初始第一項,那麼我就得根據顏色篩選出這個顏色下的所有記憶體,然後根據記憶體篩選出所有的版本。同時,只要顏色、記憶體、版本三個都選擇了,就得篩選出這個商品。
{顏色>記憶體>版本}>具體商品複製程式碼
顏色
初始化顏色,設定選擇監聽,一旦使用者選擇了某個顏色,那麼需要獲取這個顏色下的所有記憶體,並且要開始嘗試獲取商品詳情。
-
初始化顏色
/** * 初始化顏色 * * @hint */ private void initShopColor() { for (TagInfo mColor : mColors) { //初始化所有的選項為未選擇狀態 mColor.setSelect(false); } tvColor.setText(""未選擇顏色""); mColors.get(colorPositon).setSelect(true); colorAdapter = new ProperyTagAdapter(mActivity, mColors); rlShopColor.setAdapter(colorAdapter); colorAdapter.notifyDataSetChanged(); rlShopColor.setTagCheckedMode(FlowTagLayout.FLOW_TAG_CHECKED_SINGLE); rlShopColor.setOnTagSelectListener((parent, selectedList) -> { colorPositon = selectedList.get(0); strColor = mColors.get(colorPositon).getText(); // L.e("選中顏色:" + strColor); tvColor.setText(""" + strColor + """); //獲取顏色照片 initColorShop(); //查詢商品詳情 iterationShop(); }); }複製程式碼
-
獲取顏色下所有的記憶體和該顏色的照片
/** * 初始化相應的顏色的商品 獲得 圖片 */ private void initColorShop() { //初始化 選項資料 Observable.from(mMonerys).subscribe(tagInfo -> { tagInfo.setChecked(true); }); L.e("開始篩選顏色下的記憶體----------------------------------------------------------------------------------"); final List<String> tempColorMemery = new ArrayList<>(); //篩選記憶體 Observable.from(shopLists) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(0).getAttrvalue().equals(strColor)) .flatMap(childsEntity -> Observable.from(childsEntity.getAttrinfo().getAttrs())) .filter(attrsEntity -> mActivity.getString(R.string.shop_monery).equals(attrsEntity.getAttrname())) .subscribe(attrsEntity -> { tempColorMemery.add(attrsEntity.getAttrvalue()); // L.e("記憶體:"+attrsEntity.getAttrvalue()); }); Observable.from(mTempMonerys) .filter(s -> !tempColorMemery.contains(s)) .subscribe(s -> { L.e("沒有的記憶體:" + s); mMonerys.get(mTempMonerys.indexOf(s)).setChecked(false); }); momeryAdapter.notifyDataSetChanged(); L.e("篩選顏色下的記憶體完成----------------------------------------------------------------------------------"); //獲取顏色的照片 ImageHelper.loadImageFromGlide(mActivity, mImages.get(tempImageColor.indexOf(strColor)), ivShopPhoto); }複製程式碼
-
根據選中的屬性查詢是否存在該商品
/** * 迭代 選擇商品屬性 */ private void iterationShop() { // 選擇的記憶體 選擇的版本 選擇的顏色 if (strMemory == null || strVersion == null || strColor == null) return; //隱藏購買按鈕 顯示為缺貨 resetBuyButton(false); Observable.from(shopLists) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(0).getAttrvalue().equals(strColor)) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(1).getAttrvalue().equals(strVersion)) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(2).getAttrvalue().equals(strMemory)) .subscribe(childsEntity -> { L.e(childsEntity.getShopprice()); tvPrice.setText("¥" + childsEntity.getShopprice()); // ImageHelper.loadImageFromGlide(mActivity, Constant.IMAGE_URL + childsEntity.getShowimg(), ivShopPhoto); L.e("已找到商品:" + childsEntity.getName() + " id:" + childsEntity.getPid()); selectGoods = childsEntity; tvShopName.setText(childsEntity.getName()); //顯示購買按鈕 resetBuyButton(true); initShopStagesCount++; }); }複製程式碼
記憶體
通過前面一步,已經獲取了所有的記憶體。這一步只需要展示該所有記憶體,設定選擇監聽,選擇了某個記憶體後就根據 選擇顏色>選擇記憶體 獲取所有的版本。並在在其中也是要iterationShop()查詢商品的,萬一你是往回點的時候呢?
-
初始化版本
/** * 初始化記憶體 */ private void initShopMomery() { for (TagInfo mMonery : mMonerys) { mMonery.setSelect(false); Log.e(" ", "initShopMomery: " + mMonery.getText()); } tvMomey.setText(""未選擇記憶體""); mMonerys.get(momeryPositon).setSelect(true); //-----------------------------建立介面卡 momeryAdapter = new ProperyTagAdapter(mActivity, mMonerys); rlShopMomery.setAdapter(momeryAdapter); rlShopMomery.setTagCheckedMode(FlowTagLayout.FLOW_TAG_CHECKED_SINGLE); rlShopMomery.setOnTagSelectListener((parent, selectedList) -> { momeryPositon = selectedList.get(0); strMemory = mMonerys.get(momeryPositon).getText(); // L.e("選中記憶體:" + strMemory); iterationShop(); tvMomey.setText(""" + strMemory + """); iterationVersion(); }); }複製程式碼
-
根據已選擇的顏色和記憶體獲取到版本
/** * 迭代 獲取版本資訊 */ private void iterationVersion() { if (strColor == null || strMemory == null) { return; } // L.e("開始迭代版本"); Observable.from(mVersions).subscribe(tagInfo -> { tagInfo.setChecked(true); }); final List<String> iterationTempVersion = new ArrayList<>(); //1. 遍歷出 這個顏色下的所有手機 //2. 遍歷出 這些手機的所有版本 Observable.from(shopLists) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(0).getAttrvalue().equals(strColor)) .filter(childsEntity -> childsEntity.getAttrinfo().getAttrs().get(2).getAttrvalue().equals(strMemory)) .flatMap(childsEntity -> Observable.from(childsEntity.getAttrinfo().getAttrs())) .filter(attrsEntity -> attrsEntity.getAttrname().equals(mActivity.getString(R.string.shop_standard))) .subscribe(attrsEntity -> { iterationTempVersion.add(attrsEntity.getAttrvalue()); }); Observable.from(mTempVersions).filter(s -> !iterationTempVersion.contains(s)).subscribe(s -> { mVersions.get(mTempVersions.indexOf(s)).setChecked(false); }); versionAdapter.notifyDataSetChanged(); // L.e("迭代版本完成"); }複製程式碼
版本
其實到了這一步,已經算是完成了,只需要設定監聽,獲取選中的版本,然後開始查詢商品。
/**
* 初始化版本
*/
private void initShopVersion() {
for (TagInfo mVersion : mVersions) {
mVersion.setSelect(false);
}
tvVersion.setText(""未選擇版本"");
mVersions.get(versionPositon).setSelect(true);
//-----------------------------建立介面卡
versionAdapter = new ProperyTagAdapter(mActivity, mVersions);
rlShopVersion.setAdapter(versionAdapter);
rlShopVersion.setTagCheckedMode(FlowTagLayout.FLOW_TAG_CHECKED_SINGLE);
rlShopVersion.setOnTagSelectListener((parent, selectedList) -> {
versionPositon = selectedList.get(0);
strVersion = mVersions.get(versionPositon).getText();
// L.e("選中版本:" + strVersion);
iterationShop();
tvVersion.setText(""" + strVersion + """);
});
}複製程式碼
完成
最終效果圖如下:
不要在意後面的輪播圖,那其實很簡單的。
最後
正在封裝成lib
文采不是很好啊。不是很完美的表達出我自己的想法
如果有可能,能給我start嗎?
原始碼地址