Android ListView三級聯動,實現自定義地址選擇器
阿新 • • 發佈:2019-01-11
說到地址選擇器,好多小夥伴第一印象就是——wheelView~這玩意確實挺好用的^(* ̄(oo) ̄)^!
然而悲劇的故事發生了,傲嬌的老闆不喜歡wheelView那種選中條不動的效果 ~(⊙o⊙)!
好吧,其實是老闆不知道從哪個忘記名字的App看到這種效果,然後堅持要把地址選擇器搞成這樣。話不多說,先上圖:
眼尖的小夥伴,應該一眼就看出了,沒錯,就只是3個listView拼起來的效果。說到聯動效果,即拿到listView1中item對應的String,去獲取listView資料,把listView的String當成key,獲取listView2對應的value(String[])。拿ListView2中item的String,獲取ListView2的value(String[])。
已經有思路了,我們第一件事就是讓後臺給我們來份全國省市區的json檔案。然後解析檔案,拿到全國的地址資料。
/**
* 所有省
*/
private String[] mProvinceDatas;
/**
* key - 省 value - 市s
*/
private Map<String, String[]> mCitisDatasMap = new HashMap<String, String[]>();
/**
* key - 市 values - 區s
*/
private Map<String, String[]> mAreaDatasMap = new HashMap<String, String[]>();
解析資料:
/**
* 解析整個Json物件,完成後釋放Json物件的記憶體
*/
private void initDatas()
{
try
{
JSONArray jsonArray = mJsonObj.getJSONArray("citylist");
mProvinceDatas = new String[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonP = jsonArray.getJSONObject(i);// 每個省的json物件
String province = jsonP.getString("p");// 省名字
mProvinceDatas[i] = province;
JSONArray jsonCs = null;
try
{
/**
* Throws JSONException if the mapping doesn't exist or is
* not a JSONArray.
*/
jsonCs = jsonP.getJSONArray("c");
} catch (Exception e1)
{
continue;
}
String[] mCitiesDatas = new String[jsonCs.length()];
for (int j = 0; j < jsonCs.length(); j++)
{
JSONObject jsonCity = jsonCs.getJSONObject(j);
String city = jsonCity.getString("n");// 市名字
mCitiesDatas[j] = city;
JSONArray jsonAreas = null;
try
{
/**
* Throws JSONException if the mapping doesn't exist or
* is not a JSONArray.
*/
jsonAreas = jsonCity.getJSONArray("a");
} catch (Exception e)
{
continue;
}
String[] mAreasDatas = new String[jsonAreas.length()];// 當前市的所有區
for (int k = 0; k < jsonAreas.length(); k++)
{
String area = jsonAreas.getJSONObject(k).getString("s");// 區域的名稱
mAreasDatas[k] = area;
}
mAreaDatasMap.put(city, mAreasDatas);
}
mCitisDatasMap.put(province, mCitiesDatas);
}
} catch (JSONException e)
{
e.printStackTrace();
}
mJsonObj = null;
}
/**
* 從assert資料夾中讀取省市區的json檔案,然後轉化為json物件
*/
private void initJsonData()
{
try
{
StringBuffer sb = new StringBuffer();
InputStream is = context.getAssets().open("city.json");
int len = -1;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1)
{
sb.append(new String(buf, 0, len, "utf-8"));
}
is.close();
mJsonObj = new JSONObject(sb.toString());
} catch (IOException e)
{
e.printStackTrace();
} catch (JSONException e)
{
e.printStackTrace();
}
}
一開始showDialog的時候,我們需要給三個listView設定預設值:
private void selectCityDefult() {
provincePosition=0;
mAdapter1.setSelectedPosition(0);
mAdapter1.notifyDataSetInvalidated();
citys=mCitisDatasMap.get(mProvinceDatas[0]);
cityPosition=0;
mAdapter2=new TextAdapter(citys,context);
mAdapter2.setSelectedPosition(0);
listView2.setAdapter(mAdapter2);
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
cityPosition = position;
mAdapter2.setSelectedPosition(cityPosition);
mAdapter2.notifyDataSetInvalidated();
areas = mAreaDatasMap.get(citys[cityPosition]);
mAdapter3 = new TextAdapter(areas,context);
listView3.setAdapter(mAdapter3);
}
});
areasPosition=0;
areas =mAreaDatasMap.get(citys[0]);
mAdapter3 =new TextAdapter(areas,context);
mAdapter3.setSelectedPosition(0);
listView3.setAdapter(mAdapter3);
listView3.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
areasPosition=position;
province=mProvinceDatas[position];
mAdapter3.setSelectedPosition(areasPosition);
mAdapter3.notifyDataSetInvalidated();
//position為最後一個數組的position
// Toast.makeText(context,
// "provincePosition=" + provincePosition + "cityPosition=" + cityPosition + "areasPosition=" + areasPosition,
// Toast.LENGTH_LONG).show();
province=mProvinceDatas[provincePosition];
city =mCitisDatasMap.get(province)[cityPosition];
area =mAreaDatasMap.get(city)[areasPosition];
textBack.textback(province,city,area);
}
});
}
有人可能會問了,你為什麼不把listView1的setOnItemclick也放進selectCityDefult()去, 嗯哼,我覺得預設的概念是選中,ItemClick不應該包括進去,至於listView2和listView3的ItemClick是因為邏輯需要才放進去的~(⊙o⊙)!
好吧,有些人只想看怎麼用,自定義dialog的完整程式碼
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* Created by KID on 2016/12/20.
*/
public class XsAddressDialog extends AlertDialog{
private Context context;
/**
* 把全國的省市區的資訊以json的格式儲存,解析完成後賦值為null
*/
private JSONObject mJsonObj;
//省的listView
private MyListView listView1;
private TextAdapter mAdapter1;
//市的listView
private MyListView listView2;
private TextAdapter mAdapter2;
//區的listView
private MyListView listView3;
private TextAdapter mAdapter3;
/**
* 所有省
*/
private String[] mProvinceDatas;
/**
* key - 省 value - 市s
*/
private Map<String, String[]> mCitisDatasMap = new HashMap<String, String[]>();
/**
* key - 市 values - 區s
*/
private Map<String, String[]> mAreaDatasMap = new HashMap<String, String[]>();
//當前的citys
private String []citys;
//當前的areas
private String []areas;
//當前省市區的選中位置
public int provincePosition;
public int cityPosition;
public int areasPosition;
//最終選中的省,市,區
private String province;
private String city;
private String area;
public XsAddressDialog(Context context, int themeResId) {
super(context, R.style.mycustom_dialog);
this.context = context;
}
private TextBack textBack;
public interface TextBack{
void textback(String province, String city, String area);
}
public void setTextBackListener(TextBack textBack) {
this.textBack=textBack;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
private void init() {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.dialog_address, null);
ViewGroup.LayoutParams layoutParams =new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
setContentView(view,layoutParams);
//-------------------------------------------------------------------
initJsonData();
initDatas();
listView1= (MyListView) view.findViewById(R.id.listview1);
listView2=(MyListView) view.findViewById(R.id.listview2);
listView3=(MyListView) view.findViewById(R.id.listview3);
mAdapter1=new TextAdapter(mProvinceDatas,context);
listView1.setAdapter(mAdapter1);
//設定city的預設值
selectCityDefult();
listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
provincePosition = position;
mAdapter1.setSelectedPosition(provincePosition);
mAdapter1.notifyDataSetInvalidated();
citys = mCitisDatasMap.get(mProvinceDatas[provincePosition]);
mAdapter2 = new TextAdapter(citys, context);
listView2.setAdapter(mAdapter2);
mAdapter2.setSelectedPosition(0);
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
cityPosition = position;
mAdapter2.setSelectedPosition(cityPosition);
mAdapter2.notifyDataSetInvalidated();
areas = mAreaDatasMap.get(citys[cityPosition]);
mAdapter3 = new TextAdapter(areas, context);
mAdapter3.setSelectedPosition(0);
listView3.setAdapter(mAdapter3);
}
});
areas = mAreaDatasMap.get(citys[0]);
mAdapter3 = new TextAdapter(areas, context);
mAdapter3.setSelectedPosition(0);
listView3.setAdapter(mAdapter3);
}
});
}
private void selectCityDefult() {
//-------------------------------------------------------------------
provincePosition=0;
mAdapter1.setSelectedPosition(0);
mAdapter1.notifyDataSetInvalidated();
citys=mCitisDatasMap.get(mProvinceDatas[0]);
cityPosition=0;
mAdapter2=new TextAdapter(citys,context);
mAdapter2.setSelectedPosition(0);
listView2.setAdapter(mAdapter2);
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
cityPosition = position;
mAdapter2.setSelectedPosition(cityPosition);
mAdapter2.notifyDataSetInvalidated();
areas = mAreaDatasMap.get(citys[cityPosition]);
mAdapter3 = new TextAdapter(areas,context);
listView3.setAdapter(mAdapter3);
}
});
areasPosition=0;
areas =mAreaDatasMap.get(citys[0]);
mAdapter3 =new TextAdapter(areas,context);
mAdapter3.setSelectedPosition(0);
listView3.setAdapter(mAdapter3);
listView3.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
areasPosition=position;
province=mProvinceDatas[position];
mAdapter3.setSelectedPosition(areasPosition);
mAdapter3.notifyDataSetInvalidated();
//position為最後一個數組的position
// Toast.makeText(context,
// "provincePosition=" + provincePosition + "cityPosition=" + cityPosition + "areasPosition=" + areasPosition,
// Toast.LENGTH_LONG).show();
province=mProvinceDatas[provincePosition];
city =mCitisDatasMap.get(province)[cityPosition];
area =mAreaDatasMap.get(city)[areasPosition];
textBack.textback(province,city,area);
}
});
}
/**
* 解析整個Json物件,完成後釋放Json物件的記憶體
*/
private void initDatas()
{
try
{
JSONArray jsonArray = mJsonObj.getJSONArray("citylist");
mProvinceDatas = new String[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonP = jsonArray.getJSONObject(i);// 每個省的json物件
String province = jsonP.getString("p");// 省名字
mProvinceDatas[i] = province;
JSONArray jsonCs = null;
try
{
/**
* Throws JSONException if the mapping doesn't exist or is
* not a JSONArray.
*/
jsonCs = jsonP.getJSONArray("c");
} catch (Exception e1)
{
continue;
}
String[] mCitiesDatas = new String[jsonCs.length()];
for (int j = 0; j < jsonCs.length(); j++)
{
JSONObject jsonCity = jsonCs.getJSONObject(j);
String city = jsonCity.getString("n");// 市名字
mCitiesDatas[j] = city;
JSONArray jsonAreas = null;
try
{
/**
* Throws JSONException if the mapping doesn't exist or
* is not a JSONArray.
*/
jsonAreas = jsonCity.getJSONArray("a");
} catch (Exception e)
{
continue;
}
String[] mAreasDatas = new String[jsonAreas.length()];// 當前市的所有區
for (int k = 0; k < jsonAreas.length(); k++)
{
String area = jsonAreas.getJSONObject(k).getString("s");// 區域的名稱
mAreasDatas[k] = area;
}
mAreaDatasMap.put(city, mAreasDatas);
}
mCitisDatasMap.put(province, mCitiesDatas);
}
} catch (JSONException e)
{
e.printStackTrace();
}
mJsonObj = null;
}
/**
* 從assert資料夾中讀取省市區的json檔案,然後轉化為json物件
*/
private void initJsonData()
{
try
{
StringBuffer sb = new StringBuffer();
InputStream is = context.getAssets().open("city.json");
int len = -1;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1)
{
sb.append(new String(buf, 0, len, "utf-8"));
}
is.close();
mJsonObj = new JSONObject(sb.toString());
} catch (IOException e)
{
e.printStackTrace();
} catch (JSONException e)
{
e.printStackTrace();
}
}
}
使用Activity的程式碼
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btn_show_address_picker);
textView = (TextView) findViewById(R.id.tv_result);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog();
}
});
}
private void showDialog() {
final XsAddressDialog dialog = new XsAddressDialog(this,R.style.mycustom_dialog);
dialog.show();
dialog.setCancelable(true);
Window win = dialog.getWindow();
win.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = win.getAttributes();
// 設定彈出框的寬高
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = 500;
// 設定彈出框的位置
win.setGravity(Gravity.BOTTOM);
win.setAttributes(lp);
dialog.setTextBackListener(new XsAddressDialog.TextBack() {
@Override
public void textback(String province, String city, String area) {
textView.setText("選中地址是: "+province+"---"+city+"---"+area);
dialog.dismiss();
}
});
}
}