欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Android 多級聯(lián)動控件實現(xiàn)思路討論

 更新時間:2020年11月15日 08:38:57   作者:佛系編碼  
這篇文章主要介紹了詳解Android 多級聯(lián)動控件實現(xiàn)思路討論,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

最近有一個需求是選擇多級聯(lián)動數(shù)據(jù),數(shù)據(jù)級別不固定,可能是五級,可能是兩級,具體看用戶等級。

所以就需要一個多級聯(lián)動選擇控件 ,在網(wǎng)上一番搜索或找到了這個控件, Android-PickerView

這個控件在三級以內(nèi)的的聯(lián)動都沒有問題,但是最多只能到三級。

我在原有的基礎(chǔ)上做了一些擴展,主要是添加了兩個 picker

MultiWheelPickerView 可以根據(jù)數(shù)據(jù)動態(tài)生成多個滾輪,不再局限于兩個三個選項 DynamicWheelPickerView 也是動態(tài)生成,但可以一級一級的加載數(shù)據(jù)并追加滾輪。

在使用時,根據(jù)自身情況讓你的 JavaBean 實現(xiàn) IWheelItem 或者 IDynamicWheelItem 就好。

這里記錄并分享一下我的思路和實現(xiàn),也希望能和大家一起討論更好的實現(xiàn)方案。

起初,只是想根據(jù)獲取到的數(shù)據(jù)動態(tài)的生成滾輪,有多少級就生成多少個,自動排列出來就好。

在看了源碼后發(fā)現(xiàn)原來的 OptionsPickerView 里寫死了三個 WheelView ,所以最多只能是三個。

如果想動態(tài)生成 WheelView 就不能寫死,只能根據(jù)數(shù)據(jù)生成,所以我選擇使用代碼創(chuàng)建 WheelView,不使用 layout 布局固定數(shù)量了。

除了 WheelView 部分外,其他部分還都是使用原來的布局。

因為要動態(tài)顯示數(shù)據(jù),就不能使用原來的 IPickerViewData 了,使用了一個新的 IWheelItem

public interface IWheelItem {

  /**
   *
   * @return 顯示在滾輪的文本
   */
  String getShowText();

  /**
   *
   * @return 下一級的數(shù)據(jù)
   */
  <T extends IWheelItem> List<T> getNextItems();

}

只有兩個方法,返回顯示數(shù)據(jù)用來顯示在滾輪上;在選擇了一級后自動獲取下一級內(nèi)容顯示。

這種多級聯(lián)動的數(shù)據(jù),明顯有著上下級關(guān)系,我就默認(rèn)為這種結(jié)構(gòu)了,一級套著一級。

并在 WheelView 里做了調(diào)整

/**
   * 獲取所顯示的數(shù)據(jù)源
   *
   * @param item data resource
   * @return 對應(yīng)顯示的字符串
   */
  private String getContentText(Object item) {
    if (item == null) {
      return "";
    } else if (item instanceof IPickerViewData) {
      return ((IPickerViewData) item).getPickerViewText();
    } else if (item instanceof Integer) {
      //如果為整形則最少保留兩位數(shù).
      return getFixNum((int) item);
    }else if (item instanceof IWheelItem){
      return ((IWheelItem)item).getShowText();
    }
    return item.toString();
  }

First of all, 確定數(shù)據(jù)的層級,根據(jù)層級決定生成 WheelView 的數(shù)量。

/**
   * 獲取當(dāng)前 list 的層級,最深有多少層
   * 需要根據(jù)層級確定多少個滾輪
   * @param list 數(shù)據(jù)
   * @return 最深層級
   */
  private int getLevel(List<T> list) {
    int level = 0;
    if (list != null && list.size() > 0) {
      level = 1;
      int childLevel = 0;
      for (T code : list) {
        List<T> children =code.getNextItems();
        int temp = getLevel(children);
        if (temp > childLevel) {
          childLevel = temp;
        }
      }
      level += childLevel;
    }
    return level;
  }

我使用的是一個 LinearLayout 橫向排列,用來承載動態(tài)生成的 WheelView 。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="vertical">

  <include
    layout="@layout/include_pickerview_topbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/pickerview_topbar_height" />

  <LinearLayout
    android:id="@+id/ll_multi_picker"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:gravity="center"
    android:minHeight="180dp"
    android:orientation="horizontal">
  </LinearLayout>
</LinearLayout>

注意:這里有一個問題就是,如果生成的滾輪很多,會顯得比較擁擠。

知道了要生成多少個滾輪后,代碼創(chuàng)建直接添加到 LinearLayout 里了。

int level =getLevel(wheelItems);
if (level > 0) {
  //生成 滾輪
  for (int i = 0; i < level; i++) {
    WheelView wheelView = generateWheel();
    mLlContainer.addView(wheelView);
  }
  //為滾輪賦值 ,都取第一個賦值
  initWheel(wheelItems, 0);
}

生成 WheelView 之后,就是給控件賦值了,我這里默認(rèn)取第一個當(dāng)做選中的值。

只要前邊一級選中了,那就獲取它的下一級數(shù)據(jù)給下一個控件賦值,如此遞歸到最后一個。

protected void initWheel(List<T> list, int wheelIndex) {
    WheelView wheelView = (WheelView) mLlContainer.getChildAt(wheelIndex);
    if (null == wheelView) {
      Log.d(MultiWheelPickerView.class.getSimpleName(), "initWheel: 超出了范圍 " + wheelIndex + " > " + mLlContainer.getChildCount());
      return;
    }
    if (null != list && list.size() > 0) {
      wheelView.setAdapter(new MultiWheelAdapter(list));
      wheelView.setCurrentItem(0);
      wheelView.setOnItemSelectedListener(new MultiWheelItemSelector(list, wheelIndex));
      //默認(rèn)選中第一項,添加到結(jié)果里。
      T wheelItem = list.get(0);
      addToResult(wheelItem, wheelIndex);
      List<T> children = list.get(0).getNextItems();
      //有子集,繼續(xù)添加
      wheelIndex++;
      initWheel(children, wheelIndex);
    }else{
      for (int i=wheelIndex;i<mLlContainer.getChildCount();i++){
        wheelView = (WheelView) mLlContainer.getChildAt(i);
        wheelView.setAdapter(new MultiWheelAdapter(null));
      }
    }
  }

關(guān)于選中的數(shù)據(jù)和事件,和原來一樣,只是換了一種形式,使用 List 容器。

按照順序,把選中的數(shù)據(jù)都列在里面了,邏輯如下

protected void addToResult(T value, int index) {
    // 檢測是否發(fā)生了變化,需要對外釋放信號
    int size = resultList.size();
    Log.d(MultiWheelPickerView.class.getSimpleName(), "addToResult: " + index + "-->" + value + "; size->" + size);
    //上級換了人,下級全部移除掉
    while (index < size) {
      resultList.remove(index);
      size = resultList.size();
    }
    //已經(jīng)把之后的刪除了,直接添加就行了
    boolean isAddToResult =true;
    if (null!=listener){
    // 這里可以從外部判斷是否可以選擇,有的 是不需要選擇的,例如 all, 或者 “”
      isAddToResult = listener.isAddToResult(value);
    }
    if (isAddToResult) {
      resultList.add(value);
    }
    if (null!=listener){
      listener.onChange(resultList);
    }
  }

就這樣稍微改一改,一個動態(tài)多級關(guān)聯(lián)控件就有了,在使用時,讓你的 JavaBean 實現(xiàn) IWheelItem 就好。

簡單使用方式如下

MultiWheelPickerView<CodeTable> fixedPickerView;

  private void fixedPicker() {
    if (null == fixedPickerView) {
      MultiWheelPickerBuilder<CodeTable> builder = new MultiWheelPickerBuilder<>(this,
          new MultiWheelSelectListener<CodeTable>() {
            @Override
            public void onChange(List<CodeTable> result) {
              //在滾輪選擇發(fā)生變化時會被調(diào)用
              showChange(result);
            }

            @Override
            public void onSelect(List<CodeTable> result) {
              //在按下確定按鈕時會被調(diào)用
              StringBuffer buffer = new StringBuffer();
              int size = result.size();
              for (int i = 0; i < size; i++) {
                if (i != 0) {
                  buffer.append("->");
                }
                buffer.append(result.get(i).getShowText());
              }
              mTvResult.setText(buffer.toString());
            }

            @Override
            public boolean isAddToResult(CodeTable selectValue) {
              //此方法返回值會確定這個值是否可以被選中
              return !selectValue.getCode().equalsIgnoreCase("all");
            }
          });
      fixedPickerView = builder.build();
      fixedPickerView.setTitleText("行政區(qū)劃");
      fixedPickerView.setWheelItems(getPickerData());
    }
    fixedPickerView.show();
  }

雖然實現(xiàn)了多級聯(lián)動,但是在實際使用時又發(fā)現(xiàn)了不可忽視的問題: 如果數(shù)據(jù)過多,就會加載很長時間,從省級到村級,會有數(shù)萬條記錄,一次獲取過來體驗太差了,而且有崩潰的風(fēng)險。

更好的辦法是一級一級的去獲取數(shù)據(jù),選中省級再去獲取下屬的市級并追加滾輪顯示,選中市級再去獲取縣級,如此類推。

So, 接續(xù)改,因為數(shù)據(jù)也是多次獲取了,就無法確定層級了,故需要每有新的層級時添加新的 WheelView 追加到顯示容器里(突然增加一個View會出現(xiàn)橫跳的情況,最好是加入一個動畫平滑一點)。

在選中一個數(shù)據(jù)時,也要判斷是否需要去加載下一級,在我的需求里,有的是需要到村級,有的則需要到縣級。

所以具體是否要加載下一級的配置要放出來,我這里放在了數(shù)據(jù)接口上,由數(shù)據(jù)自身判斷。

在 IWheelItem 的基礎(chǔ)上擴展了一個 IDynamicWheelItem

public interface IDynamicWheelItem extends IWheelItem {
  /**
   * @return 是否需要加載下一級
   */
  boolean isLoadNext() ;
}

然后是在生成 WheelView 這里做了一些修改,根據(jù)傳入的數(shù)據(jù)生成。

也是默認(rèn)選擇了第一項,如果能被選中,則繼續(xù)生成或者去加載子級數(shù)據(jù)。

protected void generateWheel(List<T> data) {
    if (data != null && data.size() > 0) {
      //需要生成 wheel
      WheelView wheelView = generateWheel();
      wheelView.setAdapter(new ArrayWheelAdapter(data));
      mLlContainer.addView(wheelView);
      int level = mLlContainer.getChildCount() - 1;
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(data, level));
      T iWheelItem = data.get(0);
      addToResult(iWheelItem, level);
      if (canSelect(iWheelItem)) {
        List<T> nextItems = iWheelItem.getNextItems();
        if (null != nextItems && nextItems.size() > 0) {
          generateWheel(nextItems);
        } else {
          if (iWheelItem.isLoadNext()) {
            loadNext(iWheelItem, ++level);
          }
        }
      }

    }
  }

在選中一個數(shù)據(jù)后的滾輪賦值也做了修改,如果是判斷是否需要去加載下一級數(shù)據(jù)或者是否現(xiàn)有數(shù)據(jù)

在后續(xù)沒有數(shù)據(jù)的情況下,也沒有移除掉 WheelView 。一旦沒有數(shù)據(jù)就移除,會出現(xiàn)左右橫跳的情況(這里也可以做一個動畫,會顯得沒有那么突兀)。

/**
   * 設(shè)置下級Wheel 的數(shù)據(jù)
   *
   * @param current 數(shù)據(jù)
   * @param nextLevel  下一層
   */
  private void setupChildWheel(T current, int nextLevel) {
    if (mLlContainer.getChildCount() == nextLevel) {
      if (current.isLoadNext()) { //最后一級了,但是下一級仍然需要顯示
        loadNext(current, nextLevel);
      }
      return;
    }
    List<T> nextItems = current.getNextItems();
    //對于下級wheel的設(shè)置上對應(yīng)的數(shù)據(jù),即使沒有那么多級的,也不能移除view,只能將數(shù)據(jù)設(shè)置為null
    WheelView wheelView = (WheelView) mLlContainer.getChildAt(nextLevel);
    if (null != nextItems && nextItems.size() > 0) {
      //有子集
      //在 level ==count 時可能為空
      if (wheelView == null) {
        wheelView = generateWheel();
      }
      wheelView.setAdapter(new ArrayWheelAdapter(nextItems));
      wheelView.setCurrentItem(0);
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(nextItems, nextLevel));
      T wheelItem = nextItems.get(0);
      addToResult(wheelItem, nextLevel);
      nextLevel++;
      if (canSelect(wheelItem)) {
        setupChildWheel(wheelItem, nextLevel);
      }else{ //當(dāng)前已經(jīng)不能選擇了,之后的滾輪數(shù)據(jù)也必須置空
        for (int i = nextLevel; i < mLlContainer.getChildCount(); i++) {
          wheelView = (WheelView) mLlContainer.getChildAt(i);
          wheelView.setOnItemSelectedListener(null);
          wheelView.setAdapter(new MultiWheelAdapter(null));
        }
      }
    } else {
      //還需要判斷是否需要再次去獲取子集。
      //沒有子集 全部置空
      for (int i = nextLevel; i < mLlContainer.getChildCount(); i++) {
        wheelView = (WheelView) mLlContainer.getChildAt(i);
        wheelView.setOnItemSelectedListener(null);
        wheelView.setAdapter(new MultiWheelAdapter(null));
      }
      //沒有數(shù)據(jù),需要去加載
      if (canSelect(current)&&current.isLoadNext()) {
        loadNext(current, nextLevel);
      }
    }
  }

在加載數(shù)據(jù)成功后,要將數(shù)據(jù)追加到對應(yīng)的滾輪上

public void appendWheel(List<T> list, int level) {
    WheelView wheelView = null;
    if (level < mLlContainer.getChildCount()) {
      wheelView = (WheelView) mLlContainer.getChildAt(level);
    } else {
      wheelView = generateWheel();
      if (null != list && list.size() > 0)
        mLlContainer.addView(wheelView);
    }
    if (null != list && list.size() > 0) {
      wheelView.setAdapter(new MultiWheelAdapter(list));
      wheelView.setCurrentItem(0);
      T codeTable = list.get(0);
      addToResult(codeTable,level);
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(list, level));
      if (canSelect(codeTable)) { //合法數(shù)據(jù),能被選擇。
        //需要加載下一級
        level++;
        setupChildWheel(codeTable,level);
      }

    }
  }

至此,改完了,比之前那個多放出來兩個方法。

在偵聽器里擴展了一個加載下級的方法。

public interface DynamicWheelSelectListener<T extends IDynamicWheelItem>extends MultiWheelSelectListener<T> {
  /**
   * 加載下一級的數(shù)據(jù)
   * @param item 當(dāng)前數(shù)據(jù)
   * @param nextLevel 下一級的層級
   */
  void loadNextItems(T item, int nextLevel);
}

使用辦法和上面的 MultiWheelPickerView 大同小異

DynamicWheelPickerView<CodeTable> dynamicPickerView;
  private void dynamicPicker() {
    if (null == dynamicPickerView) {
      dynamicPickerView =new DynamicWheelPickerBuilder<CodeTable>(this,new DynamicWheelSelectListener<CodeTable>() {
        @Override
        public void loadNextItems(CodeTable item, int nextLevel) {
          //這里模擬的數(shù)據(jù),在加載后將 isLoadNext 設(shè)置為 false。
          List<CodeTable> child = getChild(random());
          item.setChildren(child);
          item.setLoadNext(false);
          //將數(shù)據(jù)賦值到對應(yīng)的控件上,nextLevel就是控件的位置。
          dynamicPickerView.appendWheel(child, nextLevel);
        }

        @Override
        public void onChange(List<CodeTable> result) {
          showChange(result);
        }

        @Override
        public void onSelect(List<CodeTable> result) {
          StringBuffer buffer = new StringBuffer();
          int size = result.size();
          for (int i = 0; i < size; i++) {
            if (i != 0) {
              buffer.append("->");
            }
            buffer.append(result.get(i).getShowText());
          }
          mTvResult.setText(buffer.toString());
        }

        @Override
        public boolean isAddToResult(CodeTable selectValue) {
          //是 0 的不能被選擇
          return !selectValue.getCode().equalsIgnoreCase("0");
        }
      })
          .build();
      dynamicPickerView.setTitleText("行政區(qū)劃");
      dynamicPickerView.setWheelItems(getChild(random()));

    }
    dynamicPickerView.show();
  }

具體用法可以看代碼,在這里 TestMultiWheelActivity

其他想法:

  • 目前使用 LinearLayout 包裹的,是否可以換成 RecyclerView 呢,是否能更好的控制在一行超出多少個后換行,避免擁擠。
  • 目前在動態(tài)追加滾輪時是很生硬的追加上去的,可以優(yōu)化為使用動畫平滑的過渡可能體驗更好些。

目前把代碼放在了這里 Android-PickerView

我的實現(xiàn)方式就是這樣,希望能和大家討論更好的方式。

到此這篇關(guān)于詳解Android 多級聯(lián)動控件實現(xiàn)思路討論的文章就介紹到這了,更多相關(guān)Android 多級聯(lián)動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android EditText實現(xiàn)關(guān)鍵詞批量搜索示例

    Android EditText實現(xiàn)關(guān)鍵詞批量搜索示例

    本篇文章主要介紹了Android EditText實現(xiàn)關(guān)鍵詞批量搜索示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • Android上使用ZXing識別條形碼與二維碼的方法

    Android上使用ZXing識別條形碼與二維碼的方法

    這篇文章主要介紹了Android上使用ZXing識別條形碼與二維碼的方法,需要的朋友可以參考下
    2014-08-08
  • Android進(jìn)階KOOM線上APM監(jiān)控全面剖析

    Android進(jìn)階KOOM線上APM監(jiān)控全面剖析

    這篇文章主要為大家介紹了Android進(jìn)階KOOM線上APM監(jiān)控全面剖析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Android Studio中的Gradle依賴深入講解

    Android Studio中的Gradle依賴深入講解

    Android Studio由于使用了gradle的進(jìn)行項目構(gòu)建,使我們開發(fā)app方便很多,下面這篇文章主要給大家介紹了關(guān)于Android Studio中Gradle依賴的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-09-09
  • 安卓版微信小程序跳一跳輔助

    安卓版微信小程序跳一跳輔助

    這篇文章主要為大家詳細(xì)介紹了安卓版微信小程序跳一跳輔助,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 關(guān)于Kotlin寫界面時諸多控件的點擊事件

    關(guān)于Kotlin寫界面時諸多控件的點擊事件

    這篇文章主要介紹了關(guān)于Kotlin寫界面時諸多控件的點擊事件,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • app 請求服務(wù)器json數(shù)據(jù)實例代碼

    app 請求服務(wù)器json數(shù)據(jù)實例代碼

    下面小編就為大家分享一篇app 請求服務(wù)器json數(shù)據(jù)實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Android結(jié)合kotlin使用coroutine的方法實例

    Android結(jié)合kotlin使用coroutine的方法實例

    這篇文章主要給大家介紹了關(guān)于Android結(jié)合kotlin使用coroutine的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Android編程實現(xiàn)QQ表情的發(fā)送和接收完整實例(附源碼)

    Android編程實現(xiàn)QQ表情的發(fā)送和接收完整實例(附源碼)

    這篇文章主要介紹了Android編程實現(xiàn)QQ表情的發(fā)送和接收的方法,涉及Android圖片資源、正則表達(dá)式及對話框的相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Android開發(fā)之獲取單選與復(fù)選框的值操作示例

    Android開發(fā)之獲取單選與復(fù)選框的值操作示例

    這篇文章主要介紹了Android開發(fā)之獲取單選與復(fù)選框的值操作,結(jié)合實例形式分析了Android針對單選按鈕、復(fù)選框的事件響應(yīng)、數(shù)值獲取等相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04

最新評論