flutter使用CupertinoPicker绘制一个传入数据源的省市区选择器

在这里插入图片描述

import 'package:atui/jade/bean/PCADataBean.dart';
import 'package:atui/jade/utils/JadeColors.dart';
import 'package:atui/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/*
* 传入城市数据源的省市区选择器
* 待扩展:把传入的对象类型数据源优化传入json数据,
* 并在项目中存放本地的城市json数据,当传入数据源为空时读取本地json
* */
typedef ResultBlock = void Function(CityResult result);

class CityPickerView extends StatefulWidget {
  final List<PcaDataBean> params;
  // 结果返回
  final ResultBlock onResult;
  CityPickerView({required this.onResult, required this.params});
  
  _CityPickerViewState createState() => _CityPickerViewState();
}

class _CityPickerViewState extends State<CityPickerView> {
  List<PcaDataBean> _cpaDatas = [];
  int? provinceIndex;
  int? cityIndex;
  int? areaIndex;

  late FixedExtentScrollController _provinceScrollController;
  late FixedExtentScrollController _cityScrollController;
  late FixedExtentScrollController _areaScrollController;

  CityResult result = CityResult();

  bool isShow = false;

  List get provinces {
    if (_cpaDatas.length > 0) {
      if (provinceIndex == null) {
        provinceIndex = 0;
        result.province = provinces[provinceIndex!].name;
      }
      return _cpaDatas;
    }
    return [];
  }

  List get citys {
    if (provinces.length > 0) {
      return provinces[provinceIndex!].cityVOList ?? [];
    }
    return [];
  }

  List get areas {
    if (citys.length > 0) {
      if (cityIndex == null) {
        cityIndex = 0;
        result.city = citys[cityIndex!].name;
      }
      List list = citys[cityIndex!].districtVOList ?? [];
      if (list.length > 0) {
        if (areaIndex == null) {
          areaIndex = 0;
          result.area = list[areaIndex!].name;
        }
      }
      return list;
    }
    return [];
  }

  // 保存选择结果
  _saveInfoData() {
    var prs = provinces;
    var cts = citys;
    var ars = areas;
    if (provinceIndex != null && prs.length > 0) {
      result.province = prs[provinceIndex!].name;
    } else {
      result.province = '';
    }

    if (cityIndex != null && cts.length > 0) {
      result.city = cts[cityIndex!].name;
    } else {
      result.city = '';
    }

    if (areaIndex != null && ars.length > 0) {
      result.area = ars[areaIndex!].name;
    } else {
      result.area = '';
    }
  }

  
  void dispose() {
    _provinceScrollController.dispose();
    _cityScrollController.dispose();
    _areaScrollController.dispose();
    super.dispose();
  }

  
  void initState() {
    super.initState();

    //初始化控制器
    _provinceScrollController = FixedExtentScrollController();
    _cityScrollController = FixedExtentScrollController();
    _areaScrollController = FixedExtentScrollController();

    if (widget.params == null) {
      //读取city.json数据
      _loadCitys().then((value) {
        setState(() {
          isShow = true;
        });
      });
    } else {
      _cpaDatas = widget.params;
      setState(() {
        isShow = true;
      });
    }
  }

  Future _loadCitys() async {
  	//  var cityStr = await rootBundle.loadString('assets/city.json');
    //  _cpaDatas = json.decode(cityStr) as List;

    //result默认取第一组值
    return Future.value(true);
  }

  
  Widget build(BuildContext context) {
    return Material(
      child: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            _firstView(),
            _contentView(),
          ],
        ),
      ),
    );
  }

  Widget _firstView() {
    return Container(
      height: 44,
      child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            TextButton(
              child: Text('取消',style: TextStyle(
                  color: JadeColors.grey)),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            TextButton(
              child: Text('确定'),
              onPressed: () {
                widget.onResult(result);
                Navigator.pop(context);
              },
            ),
          ]),
      decoration: BoxDecoration(
        border: Border(
            bottom: BorderSide(color: Colors.grey.withOpacity(0.1), width: 1)),
      ),
    );
  }

  Widget _contentView() {
    return Container(
      // color: Colors.orange,
      height: 200,
      child: isShow
          ? Row(
        children: <Widget>[
          Expanded(child: _provincePickerView()),
          Expanded(child: _cityPickerView()),
          Expanded(child: _areaPickerView()),
        ],
      )
          : Center(
        child: CupertinoActivityIndicator(
          animating: true,
        ),
      ),
    );
  }

  Widget _provincePickerView() {
    return Container(
      child: CupertinoPicker(
        scrollController: _provinceScrollController,
        children: provinces.map((item) {
          return Center(
            child: Text(
              item.name,
              style: TextStyle(color: Colors.black87, fontSize: 16),
              maxLines: 1,
            ),
          );
        }).toList(),
        onSelectedItemChanged: (index) {
          provinceIndex = index;
          if (cityIndex != null) {
            cityIndex = 0;
            if (_cityScrollController.positions.length > 0) {
              _cityScrollController.jumpTo(0);
            }
          }
          if (areaIndex != null) {
            areaIndex = 0;
            if (_areaScrollController.positions.length > 0) {
              _areaScrollController.jumpTo(0);
            }
          }
          _saveInfoData();
          setState(() {});
        },
        itemExtent: 36,
      ),
    );
  }

  Widget _cityPickerView() {
    return Container(
      child: citys.length == 0
          ? Container()
          : CupertinoPicker(
        scrollController: _cityScrollController,
        children: citys.map((item) {
          return Center(
            child: Text(
              item.name,
              style: TextStyle(color: Colors.black87, fontSize: 16),
              maxLines: 1,
            ),
          );
        }).toList(),
        onSelectedItemChanged: (index) {
          cityIndex = index;
          if (areaIndex != null) {
            areaIndex = 0;
            if (_areaScrollController.positions.length > 0) {
              _areaScrollController.jumpTo(0);
            }
          }
          _saveInfoData();
          setState(() {});
        },
        itemExtent: 36,
      ),
    );
  }

  Widget _areaPickerView() {
    return Container(
      width: double.infinity,
      child: areas.length == 0
          ? Container()
          : CupertinoPicker(
        scrollController: _areaScrollController,
        children: areas.map((item) {
          return Center(
            child: Text(
              item.name,
              style: TextStyle(color: Colors.black87, fontSize: 16),
              maxLines: 1,
            ),
          );
        }).toList(),
        onSelectedItemChanged: (index) {
          areaIndex = index;
          _saveInfoData();
          setState(() {});
        },
        itemExtent: 36,
      ),
    );
  }
}

class CityResult {
  /// 省市区
  String? province = '';
  String? city = '';
  String? area = '';



  CityResult({
    this.province,
    this.city,
    this.area,
  });

  CityResult.fromJson(Map<String, dynamic> json) {
    province = json['province'];
    city = json['city'];
    area = json['area'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> datas = new Map<String, dynamic>();
    datas['province'] = this.province;
    datas['city'] = this.city;
    datas['area'] = this.area;

    return datas;
  }
}

class CustomCityPicker {
  static cityPicker(BuildContext? context,provinceList,{required ResultBlock onResult}){
    showModalBottomSheet(
      context: context ?? navigatorKey.currentContext!,
      isScrollControlled: true,
      builder: (ctx) {
        return CityPickerView(
            params: provinceList,
            onResult: (res) {
              onResult(res);
            }
        );
      },
    );
  }
}

省市区接口数据源实体类

/// name : "安徽省"
/// cityVOList : [{"name":"安庆市","districtVOList":[{"name":"大观区"},{"name":"怀宁县"},{"name":"潜山市"},{"name":"宿松县"},{"name":"桐城市"},{"name":"太湖县"},{"name":"望江县"},{"name":"迎江区"},{"name":"宜秀区"},{"name":"岳西县"}]},{"name":"蚌埠市","districtVOList":[{"name":"蚌山区"},{"name":"固镇县"},{"name":"淮上区"},{"name":"怀远县"},{"name":"龙子湖区"},{"name":"五河县"},{"name":"禹会区"}]},{"name":"亳州市","districtVOList":[{"name":"利辛县"},{"name":"蒙城县"},{"name":"谯城区"},{"name":"涡阳县"}]},{"name":"滁州市","districtVOList":[{"name":"定远县"},{"name":"凤阳县"},{"name":"来安县"},{"name":"琅琊区"},{"name":"明光市"},{"name":"南谯区"},{"name":"全椒县"},{"name":"天长市"}]},{"name":"池州市","districtVOList":[{"name":"东至县"},{"name":"贵池区"},{"name":"青阳县"},{"name":"石台县"}]},{"name":"阜阳市","districtVOList":[{"name":"阜南县"},{"name":"界首市"},{"name":"临泉县"},{"name":"太和县"},{"name":"颍东区"},{"name":"颍泉区"},{"name":"颍上县"},{"name":"颍州区"}]},{"name":"淮北市","districtVOList":[{"name":"杜集区"},{"name":"烈山区"},{"name":"濉溪县"},{"name":"相山区"}]},{"name":"合肥市","districtVOList":[{"name":"包河区"},{"name":"巢湖市"},{"name":"肥东县"},{"name":"肥西县"},{"name":"庐江县"},{"name":"庐阳区"},{"name":"蜀山区"},{"name":"瑶海区"},{"name":"长丰县"}]},{"name":"淮南市","districtVOList":[{"name":"八公山区"},{"name":"大通区"},{"name":"凤台县"},{"name":"潘集区"},{"name":"寿县"},{"name":"田家庵区"},{"name":"谢家集区"}]},{"name":"黄山市","districtVOList":[{"name":"黄山区"},{"name":"徽州区"},{"name":"祁门县"},{"name":"歙县"},{"name":"屯溪区"},{"name":"休宁县"},{"name":"黟县"}]},{"name":"六安市","districtVOList":[{"name":"霍邱县"},{"name":"霍山县"},{"name":"金安区"},{"name":"金寨县"},{"name":"舒城县"},{"name":"裕安区"},{"name":"叶集区"}]},{"name":"马鞍山市","districtVOList":[{"name":"博望区"},{"name":"当涂县"},{"name":"花山区"},{"name":"含山县"},{"name":"和县"},{"name":"雨山区"}]},{"name":"宿州市","districtVOList":[{"name":"砀山县"},{"name":"灵璧县"},{"name":"泗县"},{"name":"萧县"},{"name":"埇桥区"}]},{"name":"铜陵市","districtVOList":[{"name":"郊区"},{"name":"铜官区"},{"name":"义安区"},{"name":"枞阳县"}]},{"name":"芜湖市","districtVOList":[{"name":"繁昌区"},{"name":"镜湖区"},{"name":"鸠江区"},{"name":"南陵县"},{"name":"无为市"},{"name":"湾沚区"},{"name":"弋江区"}]},{"name":"宣城市","districtVOList":[{"name":"广德市"},{"name":"旌德县"},{"name":"泾县"},{"name":"绩溪县"},{"name":"郎溪县"},{"name":"宁国市"},{"name":"宣州区"}]}]

class PcaDataBean {

  String? name;
  List<CityVoList>? cityVOList;

  PcaDataBean({
      this.name, 
      this.cityVOList,});

  PcaDataBean.fromJson(dynamic json) {
    name = json['name'];
    if (json['cityVOList'] != null) {
      cityVOList = [];
      json['cityVOList'].forEach((v) {
        cityVOList?.add(CityVoList.fromJson(v));
      });
    }
  }

PcaDataBean copyWith({  String? name,
  List<CityVoList>? cityVOList,
}) => PcaDataBean(  name: name ?? this.name,
  cityVOList: cityVOList ?? this.cityVOList,
);
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['name'] = name;
    if (cityVOList != null) {
      map['cityVOList'] = cityVOList?.map((v) => v.toJson()).toList();
    }
    return map;
  }

}

/// name : "安庆市"
/// districtVOList : [{"name":"大观区"},{"name":"怀宁县"},{"name":"潜山市"},{"name":"宿松县"},{"name":"桐城市"},{"name":"太湖县"},{"name":"望江县"},{"name":"迎江区"},{"name":"宜秀区"},{"name":"岳西县"}]

class CityVoList {

  String? name;
  List<DistrictVoList>? districtVOList;

  CityVoList({
      this.name, 
      this.districtVOList,});

  CityVoList.fromJson(dynamic json) {
    name = json['name'];
    if (json['districtVOList'] != null) {
      districtVOList = [];
      json['districtVOList'].forEach((v) {
        districtVOList?.add(DistrictVoList.fromJson(v));
      });
    }
  }
CityVoList copyWith({  String? name,
  List<DistrictVoList>? districtVOList,
}) => CityVoList(  name: name ?? this.name,
  districtVOList: districtVOList ?? this.districtVOList,
);
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['name'] = name;
    if (districtVOList != null) {
      map['districtVOList'] = districtVOList?.map((v) => v.toJson()).toList();
    }
    return map;
  }

}

/// name : "大观区"

class DistrictVoList {
  DistrictVoList({
      this.name,});

  DistrictVoList.fromJson(dynamic json) {
    name = json['name'];
  }
  String? name;
DistrictVoList copyWith({  String? name,
}) => DistrictVoList(  name: name ?? this.name,
);
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['name'] = name;
    return map;
  }

}

调用

_showCityPicker(){
    CustomCityPicker.cityPicker(context, _provinceVOList,
        onResult: (result) {
          setState(() {
            _provinceName = result.province;
            _cityName = result.city;
            _districtName = result.area;
            _showFullDistrict = '${result.province}${result.city}${result.area}';
          });
        });
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值