日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

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

瀏覽:148日期:2022-09-21 17:20:14

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

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

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

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

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

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

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

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

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

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

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

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

因?yàn)橐獎討B(tài)顯示數(shù)據(jù),就不能使用原來的 IPickerViewData 了,使用了一個(gè)新的 IWheelItem

public interface IWheelItem { /** * * @return 顯示在滾輪的文本 */ String getShowText(); /** * * @return 下一級的數(shù)據(jù) */ <T extends IWheelItem> List<T> getNextItems();}

只有兩個(gè)方法,返回顯示數(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ù)層級確定多少個(gè)滾輪 * @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; }

我使用的是一個(gè) 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: 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>

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

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

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

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

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

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)選中第一項(xiàng),添加到結(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); } }

就這樣稍微改一改,一個(gè)動態(tài)多級關(guān)聯(lián)控件就有了,在使用時(shí),讓你的 JavaBean 實(shí)現(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ā)生變化時(shí)會被調(diào)用 showChange(result); } @Override public void onSelect(List<CodeTable> result) { //在按下確定按鈕時(shí)會被調(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) { //此方法返回值會確定這個(gè)值是否可以被選中 return !selectValue.getCode().equalsIgnoreCase('all'); } }); fixedPickerView = builder.build(); fixedPickerView.setTitleText('行政區(qū)劃'); fixedPickerView.setWheelItems(getPickerData()); } fixedPickerView.show(); }

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

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

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

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

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

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

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

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

也是默認(rèn)選擇了第一項(xiàng),如果能被選中,則繼續(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); }} } } }

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

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

/** * 設(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 時(shí)可能為空 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); } } }

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

在偵聽器里擴(kuò)展了一個(gè)加載下級的方法。

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>() {@Overridepublic 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);}@Overridepublic void onChange(List<CodeTable> result) { showChange(result);}@Overridepublic 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());}@Overridepublic boolean isAddToResult(CodeTable selectValue) { //是 0 的不能被選擇 return !selectValue.getCode().equalsIgnoreCase('0');} }) .build(); dynamicPickerView.setTitleText('行政區(qū)劃'); dynamicPickerView.setWheelItems(getChild(random())); } dynamicPickerView.show(); }

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

其他想法:

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

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

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

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

標(biāo)簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久精品国产亚洲夜色av网站 | 亚洲18在线| 99tv成人| 欧美成人国产| 久热re这里精品视频在线6| 亚洲香蕉久久| 亚洲视频电影在线| 国产精品调教| 国产精品99久久精品| 久久久久久久欧美精品| 国产情侣久久| 精品亚洲a∨| 亚洲成人二区| 日韩影院免费视频| 国产精品亚洲一区二区在线观看| 精品高清久久| 精品中文字幕一区二区三区av| 久久国产精品99国产| 日韩欧美美女在线观看| 精品一二三区| 伊人久久亚洲热| 亚洲在线免费| 欧美视频久久| 亚洲播播91| 丝瓜av网站精品一区二区 | 日韩一区欧美| 日韩精品一二三区| 国产伦精品一区二区三区视频| 色婷婷色综合| 丝袜亚洲另类欧美| 欧美激情综合| 亚洲国产不卡| 久久精品免费看| 欧美不卡视频| 欧美日韩视频免费看| 日韩在线观看不卡| 日韩一区二区三区精品| 成人午夜毛片| 亚洲一区二区三区中文字幕在线观看 | 国产一区福利| 午夜欧美精品久久久久久久| 欧美午夜三级| 天堂网av成人| 青青草国产精品亚洲专区无| 久久久久久黄| 亚洲欧洲日韩| 成人精品中文字幕| 国产欧美三级| 蜜桃一区二区三区| 麻豆视频一区二区| 亚洲小说春色综合另类电影| 桃色av一区二区| 国产欧美日韩精品一区二区免费 | 青青草精品视频| 欧美女激情福利| 国产videos久久| 日本aⅴ免费视频一区二区三区| 国产精品igao视频网网址不卡日韩| 日韩区欧美区| 蜜桃av一区| 亚洲精品日本| 136国产福利精品导航网址| 美女性感视频久久| 婷婷亚洲综合| 91综合视频| 欧美亚洲色图校园春色| 影院欧美亚洲| 日韩在线免费| 久久精品国产成人一区二区三区| 在线一区二区三区视频| 欧美日韩一二| 97精品国产一区二区三区| 视频一区二区欧美| 91精品国产自产在线观看永久∴| 国产精品v一区二区三区| 亚洲欧美久久精品| 蜜桃成人av| 亚洲一区资源| 精品国产91| 欧美黄页在线免费观看| 日本一区二区三区中文字幕| 亚洲美洲欧洲综合国产一区| 日韩网站中文字幕| 福利一区二区| 国产一区二区色噜噜| 国产精一区二区| 亚洲精品亚洲人成在线观看| 欧美日韩国产探花| 国产真实久久| 中文字幕系列一区| 亚洲成人一区在线观看| 天堂av在线| 国产精品毛片一区二区在线看| 国产欧美另类| 欧美片第1页综合| 91欧美日韩在线| 日韩精品免费观看视频| 免费不卡在线观看| 免费视频最近日韩| 久久成人一区| 蜜臀av一区二区在线免费观看| 婷婷激情图片久久| 欧美~级网站不卡| 国模 一区 二区 三区| 色婷婷亚洲mv天堂mv在影片| 精品国产精品国产偷麻豆| 国产精品v亚洲精品v日韩精品| 日本视频在线一区| 国产伦精品一区二区三区千人斩| 国产欧美二区| 精品99久久| 特黄毛片在线观看| 久久青草久久| 国产精品日本| 综合国产在线| 欧美日韩亚洲一区| 国产精品一线天粉嫩av| 97se亚洲| 国产精品**亚洲精品| 国产精品伦理久久久久久| 欧美男人天堂| 红桃视频亚洲| 日韩精品视频在线看| 国产精品一区二区精品| 水蜜桃久久夜色精品一区| 久久免费国产| 国产视频一区欧美| 日本免费一区二区视频| 免费在线观看一区| 国产一区二区精品久| 免费视频亚洲| 亚洲精品无播放器在线播放| 91欧美精品| 国产黄大片在线观看| 日韩一区二区免费看| 青草国产精品| 亚洲欧洲高清| 免费日韩av片| 欧美日韩一区二区三区在线电影| 国产不卡一区| 99热免费精品| 国产乱码精品一区二区亚洲| 久久97视频| 国精品一区二区| 日韩和欧美的一区| 92国产精品| 蜜桃视频在线观看一区二区| 日韩av中文在线观看| 久久av导航| 久久中文亚洲字幕| 蜜桃免费网站一区二区三区| 加勒比视频一区| 日韩av一二三| 国产精品sm| 成人日韩在线| 欧美成a人免费观看久久| 亚洲大全视频| 国产日韩欧美一区二区三区| 麻豆91精品视频| aⅴ色国产欧美| 精品一区二区三区免费看| 日韩一区三区| 亚洲伊人精品酒店| 亚洲成人va| 四虎精品永久免费| 久久精品国产99久久| 日本成人手机在线| 私拍精品福利视频在线一区| 日韩中文字幕高清在线观看| 日本蜜桃在线观看视频| 精品三级久久| 欧美女激情福利| 偷拍精品精品一区二区三区| 精品淫伦v久久水蜜桃| 欧美日韩91| 日韩欧美一区二区三区在线观看 | 欧美亚洲在线日韩| 久久99免费视频| 日韩精品a在线观看91| 蜜桃tv一区二区三区| 精品少妇av| 欧美日韩夜夜| 亚洲性视频在线| 欧美午夜不卡影院在线观看完整版免费| 你懂的亚洲视频| 婷婷精品久久久久久久久久不卡| 亚洲精品a级片| 久久中文字幕av一区二区不卡| 久久精品国产99国产精品| 日韩精品久久久久久| 丝袜美腿亚洲一区二区图片| 婷婷激情久久| 欧美三区四区| 亚洲欧洲高清| 国产精品毛片久久| 美女免费视频一区| 久久99蜜桃| 国产精品99久久久久久董美香| 日本特黄久久久高潮| 视频一区日韩精品|