因为城市选择的数据是从服务器上拿的的,在pub上面也没有找到合适插件,索性就自己写了一个,在写的过程也遇到很多问题,其实就是三个 CupertinoPicker 组合在一起的,当时写的过程中发现 CupertinoPicker setState不更新 以及onSelectedItemChanged 调用的问题
CupertinoPicker 不更新可以通过 GlobalKey 来解决 onSelectedItemChanged 调用问题可以通过 NotificationListener监听来拿到当前的索引
这里分享一下实现代码
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:zhengda_health/app/custom_widgets/custom_text.dart';
import 'package:zhengda_health/app/http_util/http_api.dart';
import 'package:zhengda_health/app/http_util/http_util.dart';
import 'package:zhengda_health/app/support/app_color.dart';
//省市区类型
enum CityType {
province,
city,
area
}
class CityAlertView extends StatefulWidget {
CityAlertViewDelegate delegate;
CityAlertView({Key key,this.delegate}) : super(key: key);
@override
_CityAlertViewState createState() => _CityAlertViewState();
}
class _CityAlertViewState extends State<CityAlertView> {
List <CityAlertModel> _provinceList = [];
List <CityAlertModel> _cityList = [];
List <CityAlertModel> _areaList = [];
GlobalKey _provinceGlobalKey = GlobalKey();
GlobalKey _cityGlobalKey = GlobalKey();
GlobalKey _areaGlobalKey = GlobalKey();
int _provinceIndex = 0;
int _cityIndex = 0;
int _areaIndex = 0;
@override
void initState() {
// TODO: implement initState
super.initState();
_getAreaData(cityType:CityType.province,pid: '0' ,onSuccess: (){
_getAreaData(cityType: CityType.city,pid: _provinceList.first.adcode,onSuccess: (){
_getAreaData(cityType: CityType.area,pid: _cityList.first.adcode,onSuccess: (){
});
});
});
}
void _getAreaData({CityType cityType,String pid,Function onSuccess}){
HttpUtil.getHttp('${HttpApi.areaInfo}?pid=$pid',onSuccess: (res){
List<CityAlertModel> list =List<CityAlertModel>.from(res['areaLists'].map((it) => CityAlertModel.fromJson(it)));
if(cityType == CityType.province){
_provinceGlobalKey =GlobalKey();;
_provinceList = list ;
}else if(cityType == CityType.city){
_cityGlobalKey =GlobalKey();;
_cityList =list;
}else{
_areaGlobalKey =GlobalKey();;
_areaList = list;
}
setState(() {});
onSuccess();
});
}
//确定生成回调
void _confirmClick(BuildContext context ){
if(widget.delegate != null){
widget.delegate.confirmClick([_provinceList[_provinceIndex],_cityList[_cityIndex],_areaList[_areaIndex]]);
}
Navigator.of(context).pop();
}
//取消
void _canlClick(BuildContext context){
Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
return SafeArea(child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 8,),
_headerWidget(context),
Row(
children: [
_pickerViewWidget(models:_provinceList,
key:_provinceGlobalKey ,
onSelectedItemChanged: (v){
_provinceIndex = v;
_getAreaData(cityType: CityType.city,pid: _provinceList[v].adcode,onSuccess: (){
_getAreaData(cityType: CityType.area,pid: _cityList.first.adcode,onSuccess: (){
});
});
}),
_pickerViewWidget(models: _cityList,key:_cityGlobalKey,onSelectedItemChanged: (v){
_cityIndex = v;
_getAreaData(cityType: CityType.area,pid: _cityList[v].adcode,onSuccess: (){});
} ),
_pickerViewWidget(models: _areaList,key:_areaGlobalKey,onSelectedItemChanged: (v){
_areaIndex =v;
} ),
],
)
],
));
}
Widget _headerWidget(BuildContext context){
return Row(
children: [
_buttonWidget(title: '取消',textColor: Colors.black38,callback: (){
_canlClick(context);
}),
Expanded(child: Container()),
_buttonWidget(title: '确定',textColor: Colors.black,callback: (){
_confirmClick(context);
}),
],
);
}
//piceerView
Widget _pickerViewWidget({List<CityAlertModel> models,Key key,
ValueChanged<int> onSelectedItemChanged,}){
return Expanded(
child: SizedBox(
height: 200,
child: NotificationListener(
onNotification: (Notification scrollNotification) {
if (scrollNotification is ScrollEndNotification &&
scrollNotification.metrics is FixedExtentMetrics)
{
print((scrollNotification.metrics as FixedExtentMetrics).itemIndex); // Index of the list
onSelectedItemChanged((scrollNotification.metrics as FixedExtentMetrics).itemIndex);
return true;
} else {
return false;
}
},
child: CupertinoPicker(
key: key,
useMagnifier: true,
magnification: 1.2,
selectionOverlay: _selectionOverlayWidget(),
itemExtent: 34,
onSelectedItemChanged: (v){},
children: models.map((e) => _itemsWidget(e.name)).toList()),
))
);
}
// 中间分割线
Widget _selectionOverlayWidget(){
return Padding(
padding: EdgeInsets.only(left: 0, right: 0),
child: Column(
children: [
Divider(
height: 1,
color: AppColor.green86Color,
),
Expanded(child: Container()),
Divider(
height: 1,
color: AppColor.green86Color,
),
],
),
);
}
// cellItems
Widget _itemsWidget(e){
return Container(
alignment: Alignment.center,
child: CustomText(e,fontSize: 14,),
);
}
//公共button
Widget _buttonWidget({String title ,Color textColor ,VoidCallback callback}){
return InkWell(
onTap: callback,
child: Container(
alignment: Alignment.center,
padding:EdgeInsets.only(left: 16,right: 16),
height: 40,
child: CustomText(title,color: textColor,),
),
);
}
}
abstract class CityAlertViewDelegate{
void confirmClick(List<CityAlertModel> models){}
}
class CityAlertModel {
int id;
String pAdcode;
String adcode;
String name;
String level;
String pinyin;
String first;
String lng;
String lat;
CityAlertModel(
{this.id,
this.pAdcode,
this.adcode,
this.name,
this.level,
this.pinyin,
this.first,
this.lng,
this.lat});
CityAlertModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
pAdcode = json['p_adcode'];
adcode = json['adcode'];
name = json['name'];
level = json['level'];
pinyin = json['pinyin'];
first = json['first'];
lng = json['lng'];
lat = json['lat'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['p_adcode'] = this.pAdcode;
data['adcode'] = this.adcode;
data['name'] = this.name;
data['level'] = this.level;
data['pinyin'] = this.pinyin;
data['first'] = this.first;
data['lng'] = this.lng;
data['lat'] = this.lat;
return data;
}
}
调用
class _AddAddressPageState extends State<AddAddressPage> implements CityAlertViewDelegate
要implements 实现回调协议
//回调省市区
@override
void confirmClick(List<CityAlertModel> models) {}
//调用弹框
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(10)),
builder: (BuildContext context) {
return CityAlertView(delegate: this,);
});