用listview做聯動菜單,省市區爲例,附帶省市區json文件

閒話

之前沒做過聯動菜單,最近項目中要用到幾個,百度網上有不少現成的控件實現,有用到spinner的,還有用到其他控件的,不過風格不是我需要的,索性自己來實現一下,雖然不如其他大神的方法簡便,但自己寫的,還是更喜歡。

正文

製作數據源

首先要有級聯用的數據源,我這裏有一份,我忘記是從哪位大神資源上下載的了,感謝,自己製作一份json數據也行:
省市區json下載
可以把這份json文檔放在項目目錄的assets下,以便調取。

佈局文件

因爲用到listview作爲展示級聯的控件,因此,主佈局很簡單,只用建立3個listview。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:background="@color/colorBackground">

    <ListView
        android:layout_marginLeft="10dp"
        android:layout_marginRight="5dp"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:divider="@color/colorBackground"
        android:dividerHeight="2dp"
        android:id="@+id/lvProvince" />

    <ListView
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:divider="@color/colorBackground"
        android:dividerHeight="2dp"
        android:id="@+id/lvCity"/>

    <ListView
        android:layout_marginLeft="5dp"
        android:layout_marginRight="10dp"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:divider="@color/colorBackground"
        android:dividerHeight="2dp"
        android:id="@+id/lvArea"/>

</LinearLayout>

然後是item子佈局,寫demo懶一些,每個listview公用一個item佈局。
我寫佈局的時候,不知道爲什麼,如果把textview充滿父佈局,然後讓文字居中顯示android:gravity=”center”,這樣寫感覺沒什麼問題,但實際測試時發現,第一次展示數據的時候,不會有什麼問題,但是點擊幾次之後,有些item就不會在執行居中操作了,很奇怪,我也不知道爲什麼,所以才修改位textview自適應,佈局居中android:layout_centerInParent=”true”

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorWhite">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="@color/colorWord"
        android:textSize="16sp"
        android:text="省市區"
        android:gravity="center"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:id="@+id/tvPCA"/>

</RelativeLayout>

Adapter

adapter也很簡單,繼承BaseAdapter。怎樣給選中的item修改顏色,以便提醒用戶,我的處理方法是在adapter中添加一個方法setSelectPosition(int position),傳入點擊的item,在getView中,判斷當前item是否是點擊的item,如果是,就設置選中的顏色。稍微有點麻煩,不過效果還可以。

public void setSelectPosition(int position){
        this.selectPosition=position;
    }

整個adapter代碼

public class AdapterForPCA extends BaseAdapter {
    private List<String> list=null;
    private Context context;
    private int selectPosition;

    public AdapterForPCA(List<String> list, Context context){
        this.list=list;
        this.context=context;
    }

    public void setSelectPosition(int position){
        this.selectPosition=position;
    }

    @Override
    public int getCount() {
        if (list!=null){
            return list.size();
        }
        return 0;
    }

    @Override
    public Object getItem(int i) {
        return null;
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=null;
        if (view==null){
            view= LayoutInflater.from(context).inflate(R.layout.item_listview_province_city_area,null);
            viewHolder=new ViewHolder();
            viewHolder.tvPCA=Utils.findView(view,R.id.tvPCA);
            view.setTag(viewHolder);
        }else {
            viewHolder=(ViewHolder)view.getTag();
        }
        viewHolder.tvPCA.setText(list.get(i));
        viewHolder.tvPCA.setGravity(Gravity.CENTER);
        //爲了讓點擊的item顯示不同的顏色,必須在item點擊後 重新 notifyDataSetChange
        if (selectPosition==i){
            viewHolder.tvPCA.setBackgroundColor(context.getResources().getColor(R.color.colorButton));
            view.setBackgroundColor(context.getResources().getColor(R.color.colorButton));
            viewHolder.tvPCA.setTextColor(context.getResources().getColor(R.color.colorWhite));
        }else {
            viewHolder.tvPCA.setBackgroundColor(context.getResources().getColor(R.color.colorWhite));
            view.setBackgroundColor(context.getResources().getColor(R.color.colorWhite));
            viewHolder.tvPCA.setTextColor(context.getResources().getColor(R.color.colorWord));
        }
        return view;
    }

    class ViewHolder{
        TextView tvPCA;
    }
}

Activity應用

先從assets中讀取數據源

    /**
     * 從文本中讀取 省市區城市列表
     * @return
     */
    private String readPCA(){
        InputStream in=null;
        ByteArrayOutputStream out=null;
        try {
            in=getAssets().open("PCA.json");
            out=new ByteArrayOutputStream();
            byte[] b=new byte[1024];
            int length=-1;
            while ((length=in.read(b))!=-1){
                out.write(b,0,length);
            }
            return new String(out.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

讀取之後先存在保存爲JSON數組

    try {
            jsonArrayP=new JSONArray(readPCA());
        } catch (JSONException e) {
            e.printStackTrace();
        }

然後分別獲取省市區的列表

    /**
     * 獲取省列表
     */
    private void initListP(){
        try {
            listP.clear();
            if (jsonArrayP!=null) {
                for (int i = 0; i < jsonArrayP.length(); i++) {
                    JSONObject objP = jsonArrayP.getJSONObject(i);//獲取省份對象
                    listP.add(objP.getString("name"));//獲取省份名字
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根據點擊的省份,獲取該省的城市列表
     * @param provinceNum
     */
    private void setListC(int provinceNum){
        listC.clear();
        try {
            jsonObjP=jsonArrayP.getJSONObject(provinceNum);//獲取點擊的省份對象
            jsonArrayC=jsonObjP.getJSONArray("city");//獲取該省份的城市數組
            for (int i=0;i<jsonArrayC.length();i++){
                JSONObject objC=jsonArrayC.getJSONObject(i);//獲取城市數組的城市對象
                listC.add(objC.getString("name"));//獲取城市名字
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根據點擊的城市獲得地區列表
     * @param cityNum
     */
    private void setListA(int cityNum){
        listA.clear();
        try {
            jsonObjC=jsonArrayC.getJSONObject(cityNum);//根據點擊的城市對象
            JSONArray arrayA=jsonObjC.getJSONArray("area");//獲取該城市的地區列表
            for (int i=0;i<arrayA.length();i++){
                listA.add(arrayA.getString(i));//添加地區列表到list
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

最後做初始化UI 和 listview的點擊事件,註釋比較詳細,就不一一說明了

    private void initUI(){
        try {
            jsonArrayP=new JSONArray(readPCA());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        listP=new ArrayList<>();
        initListP();
        listC=new ArrayList<>();
        pro=0;
        setListC(pro);//設置默認展示的省份,根據json數組的系列號
        listA=new ArrayList<>();
        city=0;
        setListA(city);//設置默認展示哪個城市的地區


        lvProvince=Utils.findView(this,R.id.lvProvince);
        adapterP=new AdapterForPCA(listP,this);
        adapterP.setSelectPosition(pro);//設置默認選中的省份變顏色
        lvProvince.setAdapter(adapterP);
        lvProvince.setOnItemClickListener(this);

        lvCity=Utils.findView(this,R.id.lvCity);
        adapterC=new AdapterForPCA(listC,this);
        adapterC.setSelectPosition(city);//設置默認選中的城市變顏色
        lvCity.setAdapter(adapterC);
        lvCity.setOnItemClickListener(this);

        lvArea=Utils.findView(this,R.id.lvArea);
        adapterA=new AdapterForPCA(listA,this);
        adapterA.setSelectPosition(area);//設置默認選中的地區變顏色
        lvArea.setAdapter(adapterA);
        lvArea.setOnItemClickListener(this);

    }

    /**
     * 每個list 點擊事件
     * @param adapterView
     * @param view
     * @param i
     * @param l
     */
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        switch (adapterView.getId()){
            case R.id.lvProvince://點擊省列表
                pro=i;//獲得選擇的省的item
                adapterP.setSelectPosition(pro);//爲了讓選擇的item顯示不同的顏色
                //每一次選擇省,都需要把 之前選擇的市和區的item初始化爲0,默認選擇第一個
                city=0;
                area=0;
                adapterC.setSelectPosition(city);//爲了讓選擇的item顯示不同的顏色
                adapterA.setSelectPosition(area);//爲了讓選擇的item顯示不同的顏色
                //獲得點擊的省份對應的 城市列表
                setListC(pro);
                //點擊省份,顯示城市,由於還沒有點擊城市,所以默認選擇第一個城市,展示第一個城市的區列表
                setListA(city);

                //點擊省份,需要三個listview都刷新data ,以便執行 setSelectPosition ,刷新選擇的項目的顏色
                adapterP.notifyDataSetChanged();
                adapterC.notifyDataSetChanged();
                adapterA.notifyDataSetChanged();
                break;
            case R.id.lvCity:
                city=i;//點擊的城市的item
                area=0;//由於還沒有選擇區,所以區默認選擇第一個
                adapterC.setSelectPosition(city);//爲了讓選擇的item顯示不同的顏色
                adapterA.setSelectPosition(area);//爲了讓選擇的item顯示不同的顏色
                setListA(i);//獲取選擇的城市的區列表

                //點擊城市,需要刷新 城市 和 區 listview, 以便執行 setSelectPosition ,刷新選擇的項目的顏色
                adapterC.notifyDataSetChanged();
                adapterA.notifyDataSetChanged();
                break;
            case R.id.lvArea:
                area=i;//點擊的區
                adapterA.setSelectPosition(area);////爲了讓選擇的item顯示不同的顏色
                //點擊城市,需要刷新 區 listview, 以便執行 setSelectPosition ,刷新選擇的項目的顏色
                adapterA.notifyDataSetChanged();
                Toast.makeText(MainActivity.this, listP.get(pro)+""+listC.get(city)+""+listA.get(area), Toast.LENGTH_SHORT).show();
                break;
        }
    }

好了,這樣,一個簡單的級聯菜單就做好了,看看效果
這裏寫圖片描述
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章