Android開發小技巧之商品屬性篩選與商品篩選
前言
這個次為大家帶來的是一個完整的商品屬性篩選與商品篩選。什么意思?都見過淘寶、京東等愛啪啪吧,里面有個商品詳情,可以選擇商品的屬性,然后篩選出這個商品的具體型號,這樣應該知道了吧?不知道也沒關系,下面會有展示圖。
篩選屬性最終完成
關于商品篩選是有兩種方式(至少我只見到兩種):
第一種: 將所有的商品的所有屬性及詳情返回給客戶端,由客戶端進行篩選。 淘寶用的就是這種。 第二種: 將所有的屬性返回給客戶端,客戶選擇完成屬性后將屬性發送給后臺 ,再由后臺根據屬性篩選出具體商品返回給客戶端。 京東就是這樣搞的。。
兩種方式各有各的好處:
第一種:體驗性特別好,用戶感覺不到延遲,立即選中立即就篩選出了詳情。就是客戶端比較費勁。。。
第二種:客戶端比較省時間,但是體驗性太差了,你想想,在網絡不是很通暢的時候,你選擇一個商品還得等老半天。
因為當時我沒有參加到這個接口的設計,導致一直在變化。。我才不會告訴不是后臺不給力,篩選不出來才一股腦的將所有鍋甩給客戶端。
技術點
-
流式布局
商品的屬性并不是一樣長的,所以需要自動適應內容的一個控件。 推薦hongyang的博客。我就是照著那個搞的。
-
RxJava
不要問我,我不知道,我也是新手,我就是用它做出了效果,至于有沒有 用對,那我就不知道了。反正目的是達到了。
- Json解析???
準備
xml布局
這個部分的布局不是很難,只是代碼量較多,咱們就省略吧,直接看效果吧
布局完成
可以看到機身顏色、內存、版本下面都是空的,因為我們還沒有將屬性篩選出來。
數據分析
先看看整體的數據結構是怎么樣的
數據結構
每一個商品都有一個父類,僅作標識,不參與計算,比如數據中的華為P9就是一個商品的類目,在這下面有著各種屬性組成的商品子類,這才是真正的商品。
而一個詳細的商品是有三個基礎屬性所組成:
- 版本
- 內存
制式</pre>
如上圖中一個具體的商品的名稱:"華為 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 + "\""); }); }完成
最終效果圖如下:
篩選屬性最終完成
不要在意后面的輪播圖,那其實很簡單的。
來自:http://www.jianshu.com/p/af75427d7a54