Android開商品屬性篩選與商品篩選

傲寒遙發表於2019-03-01

原版程式碼請檢視這裡

前言

這個次為大家帶來的是一個完整的商品屬性篩選與商品篩選。什麼意思?都見過淘寶、京東等愛啪啪吧,裡面有個商品詳情,可以選擇商品的屬性,然後篩選出這個商品的具體型號,這樣應該知道了吧?不知道也沒關係,下面會有展示圖。

篩選屬性最終完成
篩選屬性最終完成

關於商品篩選是有兩種方式(至少我只見到兩種):

第一種: 將所有的商品的所有屬性及詳情返回給客戶端,由客戶端進行篩選。
        淘寶用的就是這種。
第二種: 將所有的屬性返回給客戶端,客戶選擇完成屬性後將屬性傳送給後臺
        ,再由後臺根據屬性篩選出具體商品返回給客戶端。
        京東就是這樣搞的。。複製程式碼

兩種方式各有各的好處:

第一種:體驗性特別好,使用者感覺不到延遲,立即選中立即就篩選出了詳情。就是客戶端比較費勁。。。

第二種:客戶端比較省時間,但是體驗性太差了,你想想,在網路不是很通暢的時候,你選擇一個商品還得等老半天。

因為當時我沒有參加到這個介面的設計,導致一直在變化。。我才不會告訴不是後臺不給力,篩選不出來才一股腦的將所有鍋甩給客戶端。

技術點

  1. 流式佈局

     商品的屬性並不是一樣長的,所以需要自動適應內容的一個控制元件。
     推薦hongyang的部落格。我就是照著那個搞的。複製程式碼
  2. RxJava

     不要問我,我不知道,我也是新手,我就是用它做出了效果,至於有沒有
     用對,那我就不知道了。反正目的是達到了。複製程式碼
  3. Json解析???

準備

  1. FlowLayout
  2. RxJava

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);
}複製程式碼

初始化屬性列表

屬性之間是有一些關係的,比如我這裡是以顏色為初始第一項,那麼我就得根據顏色篩選出這個顏色下的所有記憶體,然後根據記憶體篩選出所有的版本。同時,只要顏色、記憶體、版本三個都選擇了,就得篩選出這個商品。

{顏色>記憶體>版本}>具體商品複製程式碼

顏色

初始化顏色,設定選擇監聽,一旦使用者選擇了某個顏色,那麼需要獲取這個顏色下的所有記憶體,並且要開始嘗試獲取商品詳情。

  1. 初始化顏色

     /**
      * 初始化顏色
      *
      * @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();
         });
     }複製程式碼
  2. 獲取顏色下所有的記憶體和該顏色的照片

     /**
      * 初始化相應的顏色的商品 獲得 圖片
      */
     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);
     }複製程式碼
  1. 根據選中的屬性查詢是否存在該商品

     /**
      * 迭代 選擇商品屬性
      */
     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()查詢商品的,萬一你是往回點的時候呢?

  1. 初始化版本

     /**
      * 初始化記憶體
      */
     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();
         });
     }複製程式碼
  2. 根據已選擇的顏色和記憶體獲取到版本

     /**
      * 迭代 獲取版本資訊
      */
     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嗎?
原始碼地址

相關文章