現(xiàn)在網(wǎng)上關(guān)于省市區(qū)三聯(lián)動(dòng)的demo很多,包括之前的blog也寫過。那為啥還要再寫一次?原因是:
項(xiàng)目中這次是改版,也就是流程不動(dòng),只是改變顯示方式。接手之前的demo已經(jīng)使用spinner實(shí)現(xiàn)了省市區(qū)加載。
現(xiàn)在新需求是:
動(dòng)態(tài)加載省市區(qū),在新的一個(gè)新的頁面,點(diǎn)擊某一省(動(dòng)態(tài)獲取) 展開該省所有的市(動(dòng)態(tài)獲取),再點(diǎn)擊某一市,加載該市所有的區(qū)(也是動(dòng)態(tài)獲取);
查看了很多資料,很多demo的數(shù)據(jù)源來源:
- 本地文件,在/assets目錄也會(huì)提供存放資源文件
- 服務(wù)器返回省市區(qū)所有數(shù)據(jù),包括省市區(qū)對(duì)應(yīng)的關(guān)系,如id、pId、name
由于是改版,所以服務(wù)器數(shù)據(jù)源不會(huì)變,還是按照以前的返回方式:
1、無參請(qǐng)求,服務(wù)器返回所有的省,數(shù)據(jù)結(jié)構(gòu)為:* {*
"Results": [* {*
"ShopProvinceName":
"云南省"* },* {*
"ShopProvinceName":
"上海市"* }* ],*
"Total":
0,*
"Code":
0,*
"ServiceTime":
1492496783* }
2、點(diǎn)擊某一省,返回該省下所有的市,返回?cái)?shù)據(jù)結(jié)構(gòu)為:* {*
"Results": [* {*
"ShopCityName":
"上海市"* }* ],*
"Total":
0,*
"Code":
0,*
"ServiceTime":
1492496879* }
3、點(diǎn)擊某一市,返回該市下所有的區(qū),數(shù)據(jù)結(jié)構(gòu)為* {*
"Results": [* {*
"ShopDistrictName":
"寶山區(qū)"* },* {*
"ShopDistrictName":
"長(zhǎng)寧區(qū)"* },* {*
"ShopDistrictName":
"奉賢區(qū)"* },* {*
"ShopDistrictName":
"虹口區(qū)"* },* {*
"ShopDistrictName":
"黃浦區(qū)"* },* {*
"ShopDistrictName":
"嘉定區(qū)"* },* {*
"ShopDistrictName":
"金山區(qū)"* },* {*
"ShopDistrictName":
"閔行區(qū)"* },* {*
"ShopDistrictName":
"浦東新區(qū)"* },* {*
"ShopDistrictName":
"普陀區(qū)"* },* {*
"ShopDistrictName":
"青浦區(qū)"* },* {*
"ShopDistrictName":
"松江區(qū)"* },* {*
"ShopDistrictName":
"徐匯區(qū)"* },* {*
"ShopDistrictName":
"楊浦區(qū)"* },* {*
"ShopDistrictName":
"閘北區(qū)"* }* ],*
"Total":
0,*
"Code":
0,*
"ServiceTime":
1492496905* }
所以,不光要展示樹形結(jié)構(gòu),還要?jiǎng)討B(tài)獲取數(shù)據(jù)
如果所有的數(shù)據(jù)源都返回,不需要?jiǎng)討B(tài)加載,可以參考以下方式實(shí)現(xiàn):
ExpandableListView使用解析(三級(jí)列表的實(shí)現(xiàn))
現(xiàn)在進(jìn)入正題:
先來張效果圖
首先,樹形結(jié)構(gòu)實(shí)現(xiàn)參考的是鴻洋大神的打造任意層樹形控件,實(shí)現(xiàn)思路也是將服務(wù)器數(shù)據(jù)轉(zhuǎn)換為Node類型數(shù)據(jù),在此期間給數(shù)據(jù)源設(shè)置節(jié)點(diǎn)關(guān)系。多說無益,看代碼:
首先,獲取服務(wù)器數(shù)據(jù)源,并轉(zhuǎn)換為Node類型數(shù)據(jù)。期間伴隨有Node節(jié)點(diǎn)的點(diǎn)擊事件(獲取當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn))。
/*** 獲取省市區(qū),并將服務(wù)器數(shù)據(jù)源轉(zhuǎn)換為Node類型數(shù)據(jù)* @param jsonObject 封裝的請(qǐng)求參數(shù)* @param code 請(qǐng)求分別code* @param parentId pId 點(diǎn)擊事件傳過來的ID,作為 被點(diǎn)擊節(jié)點(diǎn) 的子節(jié)點(diǎn)的Pid* @param position 點(diǎn)擊k節(jié)點(diǎn)所在的position,*/long temp =
10000;
private void getPlace(JSONObject jsonObject,
int code,
long parentId,
int position) {app.post(
"QueryShopCity", jsonObject,
new App.CallbackJson() {
@Overridepublic void json(JSONObject data) {pd.dismiss();QueryShopCityRes queryShopCityRes = JSON.parseObject(data.toString(), QueryShopCityRes.class);ArrayList<ItemQueryShopCity> list = queryShopCityRes.getResults();
switch (code) {
case REQUEST_PROVICNE_CODE:
for (
int i =
0; i < list.size(); i++) {Node node =
new Node();node.setName(list.get(i).getShopProvinceName());node.setpId(parentId);node.setId(temp);temp++;provinceList.add(node);}CommonList.addAll(provinceList);
break;
case REQUEST_CITY_CODE:CommonList.clear();cityList.clear();districtList.clear();
for (
int i =
0; i < list.size(); i++) {Node node =
new Node();node.setName(list.get(i).getShopCityName());node.setpId(parentId);node.setId(temp);temp++;cityList.add(node);}CommonList.addAll(provinceList);CommonList.addAll(cityList);
break;
case REQUEST_DISTRICT_CODE:CommonList.clear();districtList.clear();
for (
int i =
0; i < list.size(); i++) {Node node =
new Node();node.setName(list.get(i).getShopDistrictName());node.setpId(parentId);node.setId(temp);temp++;districtList.add(node);}CommonList.addAll(provinceList);CommonList.addAll(cityList);CommonList.addAll(districtList);
break;}
try {
if (mProvinceAdapter ==
null) {Log.d(
"未點(diǎn)擊的數(shù)據(jù)源", CommonList.get(position).toString());mProvinceAdapter =
new ProvinceListAdatper<Node>(listview, FilterDrugStoreActivity.
this, CommonList,
0,
true, position);listview.setAdapter(mProvinceAdapter);}
else {mProvinceAdapter.list = CommonList;mProvinceAdapter.getDatas(position);}
/*** 樹形結(jié)構(gòu)節(jié)點(diǎn)的點(diǎn)擊事件*/mProvinceAdapter.setOnTreeNodeClickListener(
new TreeListViewAdapter.OnTreeNodeClickListener() {
@Overridepublic void onClick(Node node,
int position) {String provinceName =
"";String cityName =
"";String districtName =
"";
if (
0 == node.getLevel()) {provinceName = node.getName();JSONObject provinceObj =
new JSONObject();provinceObj.put(
"ProvinceName", provinceName);
if (node.getChildren().size() <=
0) {getPlace(provinceObj, REQUEST_CITY_CODE, node.getId(), position);}}
else if (
1 == node.getLevel()) {provinceName = node.getParent().getName();cityName = node.getName();JSONObject provinceObj =
new JSONObject();provinceObj.put(
"ProvinceName", provinceName);provinceObj.put(
"CityName", cityName);
if (node.getChildren().size() <=
0) {getPlace(provinceObj, REQUEST_DISTRICT_CODE, node.getId(), position);}}
else if (
2 == node.getLevel()) {districtName = node.getName();Node city = node.getParent();Node province = city.getParent();
ItemQueryShopCity bean =
new ItemQueryShopCity();bean.setShopProvinceName(province.getName());bean.setShopCityName(city.getName());bean.setShopDistrictName(districtName);Intent intent =
new Intent(FilterDrugStoreActivity.
this, DrugStoreActivity.class);Bundle bundle =
new Bundle();bundle.putSerializable(
"request_shop", bean);intent.putExtras(bundle);setResult(RESULT_OK, intent);finish();}}});}
catch (IllegalAccessException e) {e.printStackTrace();}
/*** 注意:不要亂刷新適配器,以致造點(diǎn)擊成屏幕的時(shí)候滾動(dòng)(如點(diǎn)擊省市區(qū)三級(jí)列表的時(shí)候會(huì)重新進(jìn)行頁面繪制)* if (adapter == null) {* listview.setadapter(adapter)* } else{* adapter.notifyDataSetChanged();* }* 在需要刷新的地方進(jìn)行notifyDataSetChanged就可以,不要使用listview.setadapter();*/
}}, error -> {app.pop(FilterDrugStoreActivity.
this, error);pd.dismiss();});}
通過:mProvinceAdapter.list = CommonList;//將請(qǐng)求到的數(shù)據(jù)傳遞給TreeListViewAdapter,進(jìn)而重新進(jìn)行數(shù)據(jù)轉(zhuǎn)換(服務(wù)器返回?cái)?shù)據(jù)—>Node樹形結(jié)構(gòu)數(shù)據(jù)),主要為了將點(diǎn)擊之后請(qǐng)求到的數(shù)據(jù)傳遞給TreeListViewAdapter,進(jìn)行數(shù)據(jù)轉(zhuǎn)換(轉(zhuǎn)換成Node類型),不能通過構(gòu)造方法傳遞數(shù)據(jù)源。因?yàn)閍dapter.notifyDataSetChanged只會(huì)重走getView()方法,所以這個(gè)時(shí)候數(shù)據(jù)源不會(huì)被構(gòu)造方法中的如下方法做任何處理。也就是刷新適配器不起作用
/*** 過濾出可見的Node*/mNodes = TreeHelper.filterVisibleNode(mAllNodes);
mInflater = LayoutInflater.from(context);
數(shù)據(jù)源轉(zhuǎn)換可以通過:mProvinceAdapter.getDatas(position);
/*** 將點(diǎn)擊之后的數(shù)據(jù)重新轉(zhuǎn)換為Node類型數(shù)據(jù),** @param position* @return*/public void covertDatas2Node(
int position) {
try {
if (list.size() >
0) {mAllNodes = TreeHelper.getSortedNodes(list,
0);}}
catch (IllegalAccessException e) {e.printStackTrace();}
/*** add by junl 2017-4-13* 去除重復(fù)元素*/if (mAllNodes.size() >
0) {
for (
int i =
0; i < mAllNodes.size(); i++) {
long id = mAllNodes.get(i).getId();
for (
int j = mAllNodes.size() -
1; j > i; j--) {
if (id == mAllNodes.get(j).getId()) {mAllNodes.remove(j);}}}}
/*** 過濾出可見的Node*/mNodes = TreeHelper.filterVisibleNode(mAllNodes);}
public void getDatas(
int pos) {covertDatas2Node(pos);
if (mNodes.get(pos).getChildren().size() >
0) {Log.d(
"點(diǎn)擊之后的數(shù)據(jù)源",mNodes.get(pos).toString());expandOrCollapse(pos);}}
經(jīng)過以上方法處理,數(shù)據(jù)源會(huì)變成Node類型的數(shù)據(jù),進(jìn)而實(shí)現(xiàn)點(diǎn)擊節(jié)點(diǎn)展開或收縮其子節(jié)點(diǎn)
適配器adapter
class ProvinceListAdatper<T> extends TreeListViewAdapter<T> {public ProvinceListAdatper(ListView mTree, Context context, List datas, int defaultExpandLevel, boolean isExpand, int pos)
throws IllegalArgumentException, IllegalAccessException {
super(mTree, context, datas, defaultExpandLevel, isExpand, pos);}
@Overridepublic View getConvertView(com.zmyseries.march.insuranceclaims.ui.discovery.Node node, int position, View convertView, ViewGroup parent) {ViewHolder viewHolder =
null;
if (convertView ==
null) {convertView = mInflater.inflate(R.layout.list_item, parent,
false);viewHolder =
new ViewHolder();viewHolder.tvName = (TextView) convertView.findViewById(R.id.tv_node_name);convertView.setTag(viewHolder);}
else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.tvName.setText(node.getName());
if (
0 == node.getLevel()) {viewHolder.tvName.setTextColor(getResources().getColor(R.color.province_text_color));}
else if (
1 == node.getLevel()) {viewHolder.tvName.setTextColor(getResources().getColor(R.color.city_text_color));}
else if (
2 == node.getLevel()) {viewHolder.tvName.setTextColor(getResources().getColor(R.color.district_text_color));}
/*** 點(diǎn)擊事件盡量設(shè)置給暴露出來的adapter;mProvinceAdapter.setOnTreeNodeClickListener{}*/
return convertView;}
private final class ViewHolder {TextView tvName;}}
代碼中注釋已經(jīng)寫的很清楚了,所以不多解釋。
由于技術(shù)局限性,難免存在問題,敬請(qǐng)指出,不勝感謝。
總結(jié)
以上是生活随笔為你收集整理的动态加载省市区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。