1. 程式人生 > >Android ListView三級聯動,實現自定義地址選擇器

Android ListView三級聯動,實現自定義地址選擇器

說到地址選擇器,好多小夥伴第一印象就是——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();
            }
        });

    }


}