用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;
        }
    }

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值