Flutter——五:自定义选择器

        城市选择器可以说是一个很常见的功能了,不过一直找不到一个顺手的现成的插件,无法根据自己的需求灵活的去创建。今天就根据我手上的需求自定义一个城市选择器。
        首先推荐一个弹窗的插件flutter_custom_dialog: ^1.0.20,用于实现城市选择器的底部弹出,具体的功能都在这个弹出层上实现。(文中只介绍城市选择实现思路,具体代码不一一赘述,文末放完整代码可自取运行

按照惯例,先上效果
Flutter——五:自定义选择器_第1张图片

实现过程
先来个模型

class CityResponse {
  int id;
  String name;

  CityResponse({this.id, this.name});
}

有了模型后就可以创建列表了,几列的就创建几个(当你各个接口返回字段等不同时,可以创建不同的“CityResponse”)

  List<CityResponse> provinceList = [];
  List<CityResponse> cityList = [];
  List<CityResponse> areaList = [];

有了列表后就可以渲染到UI上了,单列的选择器由CupertinoPicker.builder创建,因为是三列,可以封装成一个组件,传入相应的数据等内容就可以渲染相应的列表了。

  Widget buildCity(
      {List<CityResponse> list,
      FixedExtentScrollController scroll,
      int columnNum,
      Function onSelected}) {
    return Expanded(
      flex: 1,
      child: Container(
          height: 150,
          child: list.length != 0
              ? CupertinoPicker.builder(
                  scrollController: scroll,
                  itemExtent: 30,
                  diameterRatio: 3,
                  squeeze: 0.8,
                  onSelectedItemChanged: (int _index) {
                  },
                  itemBuilder: (context, index) {
                    return Center(
                        child: Text(
                      "${list[index].name}",
                      style: TextStyle(
                          fontSize: 14,
                          fontWeight: FontWeight.w600),
                    ));
                  },
                  childCount: list.length,
                )
              : Container()),
    );
  }

通过row,即可产生三列选择器。

          Row(
            children: [
              buildCity(
                  list: provinceList, scroll: scrollController[0],columnNum: 1),
              buildCity(
                  list: cityList, scroll: scrollController[1],columnNum: 2),
              buildCity(
                  list: areaList, scroll: scrollController[2],columnNum: 3),
            ],
          )

此时的选择器各列之间没有关联,若想有关联,需要通过CupertinoPicker.builder中的onSelectedItemChanged方法实现。
onSelectedItemChanged:(index){}选择时,会返回当前选择索引值。
buildCity中,为了判断是第几列,有传入columnNum,因此,当第一列时:

if(columnNum == 1){
    setState(() {
      provinceIndex = _index;
      cityIndex = 0;
      areaIndex = 0;
      cityList = getCity(id: _index);
      areaList = getArea(id: getCity(id: _index)[0].id);
    });
    if (scrollController[1].hasClients) {
      scrollController[1].jumpTo(0.0);
    }
  }

getCity(_index)可以看做通过省id获取市列表的方法,getArea(id: getCity(id: _index)[0].id)可以看做通过市id获取区列表的方法。这里需要注意的是,滑动的时候会频繁的请求,而网络请求会有延时,若前面请求的比后面的慢,则最新的会被前面的覆盖,因此需要进行处理。可以想办法减少无效请求次数,也可以在请求新的数据前先取消前一次请求,dio中有个参数为cancelToken,创建一个cancelToken传入,然后调用cancelToken.cancel()即可取消。
scrollController[1].jumpTo(0.0):当第一列选择别的省时,市列表会重置,需要将是列表的滚动位置重置到0。
第二列时以此类推,根据相应列的需求进行获取数据等操作。比如第二列选择时只需要获取区列表数据即可,第三列选择则不需要获取新数据。

大致思路即是如此,具体的下载demo运行一下即一目了然。在实际使用中有什么问题可留言。
demo下载地址

你可能感兴趣的:(Flutter,flutter,移动开发)