Android開發小技巧之商品屬性篩選與商品篩選

hojz5309 8年前發布 | 35K 次閱讀 安卓開發 Android開發 移動開發

前言

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

篩選屬性最終完成

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

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

兩種方式各有各的好處:

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

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

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

技術點

  1. 流式布局

    商品的屬性并不是一樣長的,所以需要自動適應內容的一個控件。
     推薦hongyang的博客。我就是照著那個搞的。
  2. RxJava

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

準備

  1. FlowLayout
  2. RxJava

xml布局

這個部分的布局不是很難,只是代碼量較多,咱們就省略吧,直接看效果吧

布局完成

可以看到機身顏色、內存、版本下面都是空的,因為我們還沒有將屬性篩選出來。

數據分析

先看看整體的數據結構是怎么樣的

數據結構

每一個商品都有一個父類,僅作標識,不參與計算,比如數據中的華為P9就是一個商品的類目,在這下面有著各種屬性組成的商品子類,這才是真正的商品。

而一個詳細的商品是有三個基礎屬性所組成:

  1. 版本
  2. 內存
  3. 制式</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);
    }

    初始化屬性列表

    屬性之間是有一些關系的,比如我這里是以顏色為初始第一項,那么我就得根據顏色篩選出這個顏色下的所有內存,然后根據內存篩選出所有的版本。同時,只要顏色、內存、版本三個都選擇了,就得篩選出這個商品。

    {顏色>內存>版本}>具體商品

    顏色

    初始化顏色,設置選擇監聽,一旦用戶選擇了某個顏色,那么需要獲取這個顏色下的所有內存,并且要開始嘗試獲取商品詳情。

    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 + "\"");
         });
     }

    完成

    最終效果圖如下:

    Android開發小技巧之商品屬性篩選與商品篩選

    篩選屬性最終完成

    不要在意后面的輪播圖,那其實很簡單的。

     

     

    來自:http://www.jianshu.com/p/af75427d7a54

     

 本文由用戶 hojz5309 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!