Android 三级联动 省市区选择器

Android 三级联动 省市区选择器
今天公司需求出现了一个选择区域的功能,在网上看了一下,没有看到比较直接的文章,于是自己动手写一下。
项目地址:https://gitee.com/hbhbh/area-selector

这是一篇非常用心的文章,先上效果图(没有动图不要嫌弃)


image.png

首先
省市区数据的获取地址:https://lbs.qq.com/service/webService/webServiceGuide/webServiceDistrict
API:https://apis.map.qq.com/ws/district/v1/list
去注册一下获取个key就可以用了,或者页面下面有个调用示例,可以直接用他们的key

页面XML:


    
    
        
        
        
    

GsonFormat生成实体:
小提示:同一省份下的所有市和区的ID前两位都跟省ID前两位相同,同市区下的所有区ID前四位都跟市ID前四位相同

public class CitySuccess {
    
    /**
     * status : 0
     * message : query ok
     * data_version : 20200417
     * result : [[{"id":"110101","fullname":"东城区"}]]
     */
    
    @Override
    public String toString() {
        return "CitySuccess{" +
                "status=" + status +
                ", message='" + message + '\'' +
                ", data_version='" + data_version + '\'' +
                ", result=" + result +
                '}';
    }

    private int status;
    private String message;
    private String data_version;
    private List> result;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getData_version() {
        return data_version;
    }

    public void setData_version(String data_version) {
        this.data_version = data_version;
    }

    public List> getResult() {
        return result;
    }

    public void setResult(List> result) {
        this.result = result;
    }

    public static class ResultBean {
        @Override
        public String toString() {
            return "ResultBean{" +
                    "id='" + id + '\'' +
                    ", fullname='" + fullname + '\'' +
                    '}';
        }

        /**
         * id : 110101
         * fullname : 东城区
         */


        private String id;
        private String fullname;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getFullname() {
            return fullname;
        }

        public void setFullname(String fullname) {
            this.fullname = fullname;
        }
    }
}

完整的代码:

public class MerchantDataFragment extends Fragment {

    @BindView(R.id.picker1)
    NumberPicker picker1;
    @BindView(R.id.picker2)
    NumberPicker picker2;
    @BindView(R.id.picker3)
    NumberPicker picker3;

    private List province;//省
    private List city;//市
    private List area;//区
    private List cityList;//当前的市
    private List areaList;//当前的区
    //定义数据是否已经添加完的标识
    private boolean isEnd = false;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_merchant_data, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        province = new ArrayList<>();
        city = new ArrayList<>();
        area = new ArrayList<>();
        cityList = new ArrayList<>();
        areaList = new ArrayList<>();
        //把你的Key填这里
        getCity("your key");
    }

    private void getCity(String key) {
        Call call = new RetrofitUtil().getApiInstance().getCity(key);
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                CitySuccess success = response.body();
                //获取到数据时,将数据赋值给省市区列表
                province = success.getResult().get(0);
                city = success.getResult().get(1);
                area = success.getResult().get(2);

                //初始化控件的数据
                initPicket(picker1, province);
                //获取省级数据ID的前两位
                String num = province.get(0).getId().substring(0, 2);
                //获取数据
                cityList = getList(num,city);
                //初始化控件的数据
                initPicket(picker2, cityList);
                //areaList不赋值直接传是因为 腾讯的数据第一条是北京
                //北京上海香港澳门那些城市 他们的数据只到市级不到区级 所以北京的区级数据本来就是空的
                initPicket(picker3, areaList);

                //设置监听  当省级数据改变时  需要改变市和区的数据
                picker1.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
                    @Override
                    public void onValueChange(NumberPicker numberPicker, int i, int i1) {
                        //获取省级数据ID的前两位  下面道理同上
                        String num = province.get(i1).getId().substring(0, 2);
                        //获取数据
                        cityList = getList(num,city);
                        //初始化控件
                        initPicket(picker2, cityList);
                        //获取当前市级数据ID的前四位
                        num = cityList.get(0).getId().substring(0, 4);
                        areaList = getList(num,area);
                        initPicket(picker3, areaList);
                    }
                });
                //设置监听  当省级数据改变时  只需要改变区级数据
                picker2.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
                    @Override
                    public void onValueChange(NumberPicker numberPicker, int i, int i1) {
                        String num = cityList.get(i1).getId().substring(0, 4);
                        areaList = getList(num,area);
                        initPicket(picker3, areaList);
                    }
                });
            }

            @Override
            public void onFailure(Call call, Throwable t) {

            }
        });
    }

    private List getList(String num,List list){
        List myList = new ArrayList<>();
        int length = num.length();
        for (int x = 0; x < list.size(); x++) {
            //对比市级列表Id的前两位是否跟选中的省级Id前两位相等  相等的话则代表是该省下面的市
            //对比区级列表Id的前四位是否跟选中的市级Id前四位相等  相等的话则代表是该市下面的区
            if (num.equals(list.get(x).getId().substring(0, length))) {
                myList.add(list.get(x));
                if(!isEnd){
                    isEnd = true;
                }
                continue;
            }
            if (isEnd){
                //数据添加完成后  将isEnd重置并退出循环
                isEnd = false;
                break;
            }
        }
        return myList;
    }

    private void initPicket(NumberPicker picker, List list) {
        //将数据里的地区名称抽出来  赋值给新列表
        List list1 = list.stream().map(ResultBean::getFullname).collect(Collectors.toList());
        //新建控件使用的数据数组
        String[] strings = new String[list1.size()];
        //将列表转成数组
        list1.toArray(strings);
        //数据发生变化之后  将选中值变成第一个
        picker.setValue(0);
        //当没有数据的时候(北京上海香港澳门那些没有区级数据的) 给它们设置一个空数组
        if (strings.length == 0) {
            picker.setMinValue(0);
            picker.setMaxValue(0);
            picker.setDisplayedValues(new String[]{" "});
            return;
        }
        //设置数据不循环
        picker.setWrapSelectorWheel(false);
        picker.setMinValue(0);
        picker.setDisplayedValues(strings);
        picker.setMaxValue(strings.length - 1);
        //设置数据不可编辑
        picker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
    }
}

我已经尽可能的写多一点注释了,不然我怕我以后看到这个代码都不知道是啥,本来并没有把getList方法抽出来,看起来会很臃肿,但是代码会比较好理解一点,还是抽出来整洁一点。
那个isEnd的存在,主要是在将所有需要添加进数组的数据遍历完之后,不再遍历下面别的省市的数据,能提升一点蚊子腿性能,我的手机没有加isEnd遍历4ms,加了isEnd遍历0ms,所以当数据量大的时候还是有点用处的。
有哪里写错或者哪里可以优化的话,可以在下面告诉我哦。

你可能感兴趣的:(Android 三级联动 省市区选择器)