用listview做联动菜单,省市区为例,附带省市区json文件

来源:互联网 发布:拓扑算法 编辑:程序博客网 时间:2024/06/03 03:21

闲话

之前没做过联动菜单,最近项目中要用到几个,百度网上有不少现成的控件实现,有用到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;        }    }

好了,这样,一个简单的级联菜单就做好了,看看效果
这里写图片描述
这里写图片描述

2 0
原创粉丝点击