Flutter-位置选择器
狗子自导自演-《佬kei圣_裴ker》
ps: 内心戏真多[白眼] ,不就是locationPicker吗?
预告片(截图)
编剧(插件)
flutter_picker: ^1.1.5
// address_picker: ^0.0.1 狗子直接下载这个插件的代码
// 用到了 address_manager.dart和address_model.dart文件
主演(PickerHelper及其他剧组借来的address_manager和address_model)
- 自行创建PickerHelper (参考了一位博主的文章 微微加了点料)
import 'package:album/common/address_manager.dart';
import 'package:album/common/address_model.dart';
import 'package:album/practice/practice_address_location.dart';
import 'package:flutter/material.dart';
import 'package:flutter_picker/flutter_picker.dart';
const double _kPickerSheetHeight = 216.0;
const double _kPickerItemHeight = 32.0;
typedef PickerConfirmCityCallback = Function(List<dynamic>,List<int>);
class PickerHelper {
static final textDarkGrayColor = Color.fromRGBO(64, 64, 64, 1.0);
///普通简易选择器
static void openSimpleDataPicker<T>(
BuildContext context, {
@required List<T> list,
String title,
@required T value,
PickerDataAdapter adapter,
@required PickerConfirmCallback onConfirm,
}) {
var incomeIndex = 0;
if (list != null) {
for (int i = 0; i < list.length; i++) {
if (list[i] == value) {
incomeIndex = i;
break;
}
}
}
openModalPicker(context,
adapter: adapter ??
PickerDataAdapter(
pickerdata: list,
isArray: false,
),
onConfirm: onConfirm,
selecteds: [incomeIndex],
title: title);
}
///数字选择器
static void openNumberPicker(
BuildContext context, {
String title,
List<NumberPickerColumn> datas,
NumberPickerAdapter adapter,
@required PickerConfirmCallback onConfirm,
}) {
openModalPicker(context,
adapter: adapter ?? NumberPickerAdapter(data: datas ?? []),
title: title,
onConfirm: onConfirm);
}
///日期选择器
static void openDateTimePicker(
BuildContext context, {
String title,
DateTime maxValue,
DateTime minValue,
DateTime value,
DateTimePickerAdapter adapter,
@required PickerConfirmCallback onConfirm,
}) {
openModalPicker(context,
adapter: adapter ??
DateTimePickerAdapter(
type: PickerDateTimeType.kYMD,
isNumberMonth: true,
yearSuffix: "年",
maxValue: maxValue,
minValue: minValue,
value: value ?? DateTime.now(),
monthSuffix: "月",
daySuffix: "日"),
title: title,
onConfirm: onConfirm);
}
///地址选择器
static void openCityPicker(BuildContext context,
{String title,
@required PickerConfirmCityCallback onConfirm,
List<int> selectCityIndex}) async {
/* 用于array
* [
* {'一级标题1':
* [ {'二级标题1' : ['三级标题1','三级标题2']},
* {'二级标题2' : ['三级标题1','三级标题2']},
* ],
* '一级标题1':
* [ {'二级标题1' : ['三级标题1','三级标题2']},
* {'二级标题2' : ['三级标题1','三级标题2']},
* ],
* },
* ]
* */
List<AddressProvince> provinces = await AddressManager.loadAddressData(context);
openModalPicker(context,
adapter: PickerDataAdapter(
data: provinces.map((addressProvince) {
var province = addressProvince.province;
var cities = addressProvince.cities;
return PickerItem(
text: Center(
child: Text(
province,
style: TextStyle(color: textDarkGrayColor,fontSize: 17),
),
),
value: province,
children: cities.map((cityModel) {
var cityStr = cityModel.city;
return PickerItem(
text: Center(
child: Text(
cityStr,
style: TextStyle(color: textDarkGrayColor,fontSize: 17),
),
),
value: cityStr,
children: cityModel.district.map((districtModel) {
var area = districtModel.area;
return PickerItem(
text: Center(
child: Text(
area,
style: TextStyle(color: textDarkGrayColor,fontSize: 17),
),
),
value: area
);
}).toList(),
);
}).toList(),
);
}).toList()
),
title: title, onConfirm: (pick, value) {
onConfirm(pick.adapter.getSelectedValues(),value);
},selecteds: selectCityIndex ?? [0,0,0]);
}
static void openModalPicker(
BuildContext context, {
@required PickerAdapter adapter,
String title,
List<int> selecteds,
@required PickerConfirmCallback onConfirm,
}) {
new Picker(
adapter: adapter,
title: new Text(title ?? "",style: Utils.getNormalTextStyle(17),),
selecteds: selecteds,
cancelText: '取消',
confirmText: '确定',
cancelTextStyle: TextStyle(color: Colors.black,fontSize: 16.0),
confirmTextStyle: TextStyle(color: Colors.black,fontSize: 16.0),
textAlign: TextAlign.right,
itemExtent: _kPickerItemHeight,
height: _kPickerSheetHeight,
selectedTextStyle: TextStyle(color: textDarkGrayColor,fontSize: 17),
onConfirm: onConfirm,
).showModal(context);
}
}
场地(界面)
import 'package:album/common/picker_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// Utils 是临时创建的 (小朋友们自行归位nao~)
class Utils {
// 获取屏幕宽度 (狗子(我本人) 放到了common.dart里)
static double kScreenWidth(BuildContext context) => MediaQuery.of(context).size.width;
// 项目中通用背景色 (有条件的可以单独放在color_marco.dart 文件自己建哈)
static final backGrayColor = Color.fromRGBO(249, 249, 249, 1.0);
// 文字通用样式 方便统一改字体
static TextStyle getNormalTextStyle(double fontSize,{Color fontColor = Colors.black,FontWeight fontWeight}) {
return TextStyle(
color: fontColor,
fontWeight: fontWeight,
fontSize: fontSize,
);
}
// base navigationBar
static AppBar getCustomAppBar(String title) {
return AppBar(
iconTheme: IconThemeData(
color: Colors.black,
),
backgroundColor: Color.fromRGBO(247, 247, 247, 1.0),
brightness: Brightness.light,
centerTitle: true,
title: Text(
title,
style: Utils.getNormalTextStyle(17),
),
elevation: 2.0,
);
}
}
class PracticeAddressLocation extends StatefulWidget {
@override
_PracticeAddressLocationState createState() => _PracticeAddressLocationState();
}
class _PracticeAddressLocationState extends State<PracticeAddressLocation> {
// 小朋友可以把这个些杂七杂八的放到 viewModel中 狗子为了方便直接整了
// --------- 以下这堆便是杂七杂八 ---------
// 标题
var titles = ['地区'];
// 地区
List<int> locationSelectIndexs;
List<dynamic> location;
// 隐藏键盘 void可不写 狗子(小编本人)不习惯
void hiddenKeyboard() {
FocusScope.of(context).requestFocus(FocusNode());
}
// --------- 以上这堆便是杂七杂八 ---------
// 点击事件
void tapActions(actionName) {
// 主戏
if (actionName == '地区') {
PickerHelper.openCityPicker(context, onConfirm: (selectInfo,selectLocation) {
location = selectInfo;
locationSelectIndexs = selectLocation;
setState(() {});
},title: '选择地区',selectCityIndex: locationSelectIndexs);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: Utils.getCustomAppBar('编辑资料'),
body: Container(
child: GestureDetector(
onTap: hiddenKeyboard,
child: ListView.builder(
itemBuilder: (context,index) {
var title = titles[index];
// 用处: 当有头像的情况 在未选择头像的情况下 显示promptLabel
var offstage = false;
return Container(
color: Colors.white,
height: offstage == true ? 64 : 57,
child: Column(
children: <Widget>[
// tile 默认高度56
Expanded(
child: Container(
alignment: Alignment.center,
child: ListTile(
leading: Text('地区',style: Utils.getNormalTextStyle(16),),
trailing: GestureDetector(
child: Container(
width: 200,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Stack(
alignment: Alignment.centerRight,
children: <Widget>[
Offstage( // 当有选择头像这种情况的时候
offstage: false,
child: Container(child: TextField(
decoration: InputDecoration(
hintText: '未选择',
border: InputBorder.none
),
textAlign: TextAlign.right,
cursorColor: Colors.red, // 修改光标颜色
enabled: false,
// controller: TextEditingController(text: '我是默认文字'),
keyboardType: TextInputType.number, // 键盘类型
inputFormatters: [ // 输入框文字限制
LengthLimitingTextInputFormatter(11),
],
onChanged: (text) {
},
)),
),
// 有头像的情况(与当前文章无关 可忽略)
Offstage(
offstage: !offstage,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(2)),
child: Container(
width: 50,
height: 50,
// child: Image(),
),
),
),
],
),
),
Container(child: Icon(Icons.keyboard_arrow_right),),
],
),
),
),
onTap: () {
tapActions(title);
},
),
),
),
Offstage(
offstage: false,
child: Container(height: 1,color: Utils.backGrayColor,),
)
],
),
);
},itemCount: titles.length,
),
),
),
);
}
}