史上最好用的Android省市区选择,三级联动

Android省市区选择三级联动效果,一个不大不小的功能,就算你做过,但是没有相关的代码直接写,也要花掉你至少半天时间。

下面我写出我的实现过程(思路绝对清晰)。

先上效果图


一,准备数据

我是用的本地的json数据(走网络的话太慢,每次都要请求),放在asserts中。格式如下:

[{
    "name": "河北省",
    "city": [
      {
        "name": "石家庄市",
        "area": [
          "长安区",
          "桥东区",
          "桥西区",
          "新华区",
          "郊  区",
          "井陉矿区",
          "井陉县",
          "正定县",
          "栾城县",
          "行唐县",
          "灵寿县",
          "高邑县",
          "深泽县",
          "赞皇县",
          "无极县",
          "平山县",
          "元氏县",
          "赵  县",
          "辛集市",
          "藁",
          "晋州市",
          "新乐市",
          "鹿泉市"
        ]
      },......]
二,解析数据

首先根据json生成Province对象

然后通过getAssets().open("citylist.json");获取文件输入流,接着转成字节,最终获取字符串。

然后用Gson解析字符串得到Province的List对象。由于读文件是IO操作,这里我用了RxJava,代码如下:

/**
     * 从assert文件夹中获取json数据
     */
    private void initJsonData() {

        Observable.create(new ObservableOnSubscribe<List<Province>>() {
            @Override
            public void subscribe(ObservableEmitter<List<Province>> emitter) throws Exception {
                List<Province> provinces = new ArrayList<>();
                try {
                    StringBuffer sb = new StringBuffer();
                    InputStream is = getAssets().open("citylist.json");//打开json数据
                    byte[] by = new byte[is.available()];//转字节
                    int len = -1;
                    while ((len = is.read(by)) != -1) {
                        sb.append(new String(by, 0, len, "utf8"));//根据字节长度设置编码
                    }
                    is.close();// 关闭流
                    // 通过Gson将字符串转成对象list
                    Gson gson = new Gson();
                    provinces = gson.fromJson(sb.toString(), new TypeToken<List<Province>>() {
                    }.getType());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    emitter.onNext(provinces);
                }
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<Province>>() {
                    @Override
                    public void accept(List<Province> provinces) throws Exception {
                        if (provinces != null && provinces.size() > 0) {
                            RegionSelectActivity.this.provinces = provinces;
                            // 显示数据
                            showData();
                        }
                    }
                });
    }
三,显示数据

RxJava异步读取数据后就可以显示了,这里用了三个Spinner来分别显示省,市,区数据。

显示的思路大家都清楚,这里不再赘述,代码如下

/**
     * 展示数据
     */
    private void showData() {
        for (Province province : provinces) {
            provinceList.add(province.getName());
        }
        // 显示省份数据
        spProvince.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, provinceList));
        spProvince.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                provincePosition = position;
                provinceName = provinceList.get(position);
                // 获取当前省份对应的城市list
                cityList.clear();
                List<Province.CityBean> cityBeans = provinces.get(position).getCity();
                for (Province.CityBean city : cityBeans) {
                    cityList.add(city.getName());
                }
                // 刷新城市列表
                spCity.setSelection(0);
                cityName = cityList.get(0);
                cityAdapter.notifyDataSetChanged();

                // 刷新城区列表
                updateArea(0);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        // 显示城市数据
        spCity.setAdapter(cityAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, cityList));
        spCity.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                cityPosition = position;
                cityName = cityList.get(position);
                // 刷新城区列表
                updateArea(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        // 显示城区数据
        spArea.setAdapter(areaAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, areaList));
        spArea.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                areaName = areaList.get(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
四,高德地图获取当前城市

调用了高德地图,抽象成了BaseLocationActivity,用的时候只需要继承自它,然后实现抽象方法LocationResult,即可拿到结果。

模拟器上获取不到数据,所以没有显示,在真机上是可以正常获取数据的

代码地址:







  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值