Flutter城市选择器插件luo_city_picker的使用
Flutter城市选择器插件luo_city_picker的使用
地址选择器
由于地址选择的数据来源会更新,为了统一,在后台配置一份城市数据,前端获取,否则各个平台都配置一份数据,维护会很麻烦,而且有可能每个平台城市的数据结构都不一样。
本库就是由此而来,数据从后台实时获取,只要解析成固定的数据结构就可以。
Demo
导入方式
dependencies:
luo_city_picker: ^0.0.1
使用方法
1. 简单使用
CityPicker.show(context: context, cityPickerListener: this);
2. 多配置的使用
CityPicker.show(
context: context,
// 动画控制器
animController: _animationController,
// 背景透明度
opacity: 0.5,
// 点击外部是否消失
dismissible: true,
// 高度
height: 400,
// 标题高度
titleHeight: 50,
// 顶部圆角
corner: 20,
// 背景颜色
backgroundColor: Colors.white
// 距离左边的间距
paddingLeft: 15,
// 标题组件
titleWidget: Container(
padding: EdgeInsets.only(left: 15),
child: Text(
'请选择地址',
style: TextStyle(
color: Colors.black54,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
// 选择文字
selectText: "请选择",
// 关闭图标组件
closeWidget: Icon(Icons.close),
// tab 高度
tabHeight: 40,
// 是否显示指示器
showTabIndicator: _showTabIndicator,
// tab 间隔
tabPadding: 15,
// tab 指示器颜色
tabIndicatorColor: Theme.of(context).primaryColor,
// tab 指示器高度
tabIndicatorHeight: 2,
// tab 字体大小
labelTextSize: 15,
// tab 选中的字体颜色
selectedLabelColor: Theme.of(context).primaryColor,
// tab 未选中的字体颜色
unselectedLabelColor: Colors.black54,
// 列表 item 头部高度
itemHeadHeight: 30,
// 列表 item 头部背景颜色
itemHeadBackgroundColor: Colors.white,
// 列表 item 头部分割线颜色
itemHeadLineColor: Colors.black,
// 列表 item 头部分割线高度
itemHeadLineHeight: 0.1,
// 列表 item 头部文字样式
itemHeadTextStyle: TextStyle(fontSize: 15, color: Colors.black),
// 列表 item 高度
itemHeight: 40,
// 索引组件宽度
indexBarWidth: 28,
// 索引组件 item 高度
indexBarItemHeight: 20,
// 索引组件背景颜色
indexBarBackgroundColor: Colors.black12,
// 索引组件文字样式
indexBarTextStyle: TextStyle(fontSize: 14, color: Colors.black54),
// 列表选中的图标组件
itemSelectedIconWidget:
Icon(Icons.done, color: Theme.of(context).primaryColor, size: 16),
// 列表选中的文字样式
itemSelectedTextStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor),
// 列表未选中的文字样式
itemUnSelectedTextStyle: TextStyle(fontSize: 14, color: Colors.black54),
// 初始默认地址
initialAddress: _selectedAddress,
cityPickerListener: this,
);
3. 监听事件
class HomeWidgetState extends State<HomeWidget> with SingleTickerProviderStateMixin implements CityPickerListener {
// ... 其他代码 ...
[@override](/user/override)
Future<List<AddressNode>> onDataLoad(int index, String code, String name) async {
debugPrint("onDataLoad --- $index $name");
/// 从后台获取所有省市区三级数据,Map结构
var allCityList = HttpUtils.allCityList;
/// 用户选择的省,有带选择的城市列表,Map结构
Map selectProvince = {};
/// 用户选择的城市,有带选择的区列表,Map结构
Map selectCity = {};
if (index == 0) {
return getTargetList(allCityList);
} else if (index == 1) {
for (Map province in allCityList) {
if (province["code"] == code && province["name"] == name) {
selectProvince = province;
break;
}
}
List cityList = selectProvince["children"] ?? [];
return getTargetList(cityList);
} else if (index == 2) {
List cityList = selectProvince["children"] ?? [];
for (Map city in cityList) {
if (city["code"] == code && city["name"] == name) {
selectCity = city;
break;
}
}
List districtList = selectCity["children"] ?? [];
return getTargetList(districtList);
} else {
return [];
}
}
List<AddressNode> getTargetList(List<dynamic> list) {
return list
.map((item) => AddressNode(
name: item['name'],
code: item['code'],
letter: PinyinHelper.getFirstWordPinyin(item['name']).substring(0, 1).toUpperCase(),
))
.toList();
}
[@override](/user/override)
void onFinish(List<AddressNode> data) {
String newCity = "";
for (int i = 0; i < data.length; i++) {
if (i < data.length - 1) {
newCity += "${data[i].name},";
} else {
newCity += "${data[i].name}";
}
}
_addressArea = newCity;
_selectData = data;
setState(() {});
}
}
完整示例Demo
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:luo_city_picker/city_picker.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:lpinyin/lpinyin.dart';
import 'package:provider/provider.dart';
import 'http/http_util.dart';
import 'provider/theme_provider.dart';
import 'view/item_text.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: ThemeProvider()),
],
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, _) {
Color color = themeProvider.themeColor;
return MaterialApp(
title: 'CityPickerExample',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: color,
dialogBackgroundColor: Colors.white,
bottomSheetTheme: BottomSheetThemeData(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width,
)),
),
home: HomeWidget(),
);
},
),
);
}
}
class HomeWidget extends StatefulWidget {
[@override](/user/override)
HomeWidgetState createState() => HomeWidgetState();
}
class HomeWidgetState extends State<HomeWidget> with SingleTickerProviderStateMixin implements CityPickerListener {
AnimationController? _animationController;
String _addressArea = "请选择地区";
Color _themeColor = Colors.blue;
Color _backgroundColor = Colors.white;
double _height = 500.0;
double _opacity = 0.5;
double _corner = 20;
bool _dismissible = true;
bool _showTabIndicator = true;
List<AddressNode> _selectData = [];
// List<AddressNode> _selectCity = [];
// List<AddressNode> _selectArea = [];
// List<AddressNode> _selectStreet = [];
/// 0: 省
/// 1: 市
/// 2: 地区
/// 3: 街道
int _currentType = 0;
[@override](/user/override)
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
);
}
void show(List<AddressNode> initData) {
CityPicker.show(
context: context,
animController: _animationController,
opacity: _opacity,
dismissible: _dismissible,
height: _height,
titleHeight: 50,
corner: _corner,
backgroundColor: _backgroundColor,
paddingLeft: 15,
titleWidget: Text(
'请选择地址',
style: TextStyle(
color: Colors.black54,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
selectText: "请选择",
closeWidget: Icon(Icons.close),
tabHeight: 40,
showTabIndicator: _showTabIndicator,
tabPadding: 15,
tabIndicatorColor: Theme.of(context).primaryColor,
tabIndicatorHeight: 2,
labelTextSize: 15,
selectedLabelColor: Theme.of(context).primaryColor,
unselectedLabelColor: Colors.black54,
itemHeadHeight: 30,
itemHeadBackgroundColor: _backgroundColor,
itemHeadLineColor: Colors.black,
itemHeadLineHeight: 0.1,
itemHeadTextStyle: TextStyle(fontSize: 15, color: Colors.black),
itemHeight: 40,
indexBarWidth: 28,
indexBarItemHeight: 20,
indexBarBackgroundColor: Colors.black12,
indexBarTextStyle: TextStyle(fontSize: 14, color: Colors.black54),
itemSelectedIconWidget:
Icon(Icons.done, color: Theme.of(context).primaryColor, size: 16),
itemSelectedTextStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor),
itemUnSelectedTextStyle: TextStyle(fontSize: 14, color: Colors.black54),
initialAddress: initData,
cityPickerListener: this,
);
}
Widget _buildTheme() {
return InkWell(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('选择颜色'),
content: SingleChildScrollView(
child: BlockPicker(
pickerColor: _themeColor,
onColorChanged: (color) {
setState(() {
_themeColor = color;
});
Provider.of<ThemeProvider>(context, listen: false).setTheme(color);
},
),
),
);
},
);
},
child: Container(
color: _themeColor,
width: double.infinity,
padding: EdgeInsets.all(10),
margin: EdgeInsets.fromLTRB(80, 10, 80, 10),
),
);
}
Widget _buildColor() {
return InkWell(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('选择颜色'),
content: SingleChildScrollView(
child: BlockPicker(
pickerColor: _backgroundColor,
onColorChanged: (color) {
setState(() {
_backgroundColor = color;
});
},
),
),
);
},
);
},
child: Container(
color: _backgroundColor,
width: double.infinity,
padding: EdgeInsets.all(10),
margin: EdgeInsets.fromLTRB(80, 10, 80, 10),
),
);
}
Widget _buildOpacity() {
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: Slider(
value: _opacity,
min: 0.01,
max: 1.0,
divisions: 100,
activeColor: Theme.of(context).primaryColor,
inactiveColor: Colors.grey,
onChanged: (double) {
setState(() {
_opacity = double.toDouble();
});
},
),
),
Text("${_opacity.toStringAsFixed(2)}")
],
);
}
Widget _buildDismissible() {
return Container(
alignment: Alignment.centerRight,
child: Switch(
value: _dismissible,
activeColor: Theme.of(context).primaryColor,
onChanged: (bool val) {
setState(() {
_dismissible = !_dismissible;
});
},
));
}
Widget _buildHeight() {
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: Slider(
value: _height,
min: 200,
max: 600,
divisions: 100,
activeColor: Theme.of(context).primaryColor,
inactiveColor: Colors.grey,
onChanged: (double) {
setState(() {
_height = double.toDouble();
});
},
),
),
Text("${_height.toStringAsFixed(2)}")
],
);
}
Widget _buildCorner() {
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: Slider(
value: _corner,
min: 0.0,
max: 30,
divisions: 100,
activeColor: Theme.of(context).primaryColor,
inactiveColor: Colors.grey,
onChanged: (double) {
setState(() {
_corner = double.toDouble();
});
},
),
),
Text("${_corner.toStringAsFixed(2)}")
],
);
}
Widget _buildIndicator() {
return Container(
alignment: Alignment.centerRight,
child: Switch(
value: _showTabIndicator,
activeColor: Theme.of(context).primaryColor,
onChanged: (bool val) {
setState(() {
_showTabIndicator = !_showTabIndicator;
});
},
));
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('城市选择器'),
backgroundColor: Theme.of(context).primaryColor,
),
body: SingleChildScrollView(
child: Column(
children: [
ItemTextWidget(
title: '选择地区',
subWidget: InkWell(
onTap: () {
_currentType = 0;
setState(() {});
show(_selectData);
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 15),
child: Text(_addressArea),
),
),
),
ItemTextWidget(title: '主题颜色', subWidget: _buildTheme()),
ItemTextWidget(title: '透明度', subWidget: _buildOpacity()),
ItemTextWidget(title: '外部点击消失', subWidget: _buildDismissible()),
ItemTextWidget(title: '弹窗背景颜色', subWidget: _buildColor()),
ItemTextWidget(title: '弹窗高度', subWidget: _buildHeight()),
ItemTextWidget(title: '顶部圆角', subWidget: _buildCorner()),
ItemTextWidget(title: '显示 Indicator', subWidget: _buildIndicator()),
],
),
),
);
}
[@override](/user/override)
Future<List<AddressNode>> onDataLoad(int index, String code, String name) async {
debugPrint("onDataLoad --- $index $name");
/// 从后台获取所有省市区三级数据,Map结构
var allCityList = HttpUtils.allCityList;
/// 用户选择的省,有带选择的城市列表,Map结构
Map selectProvince = {};
/// 用户选择的城市,有带选择的区列表,Map结构
Map selectCity = {};
if (index == 0) {
return getTargetList(allCityList);
} else if (index == 1) {
for (Map province in allCityList) {
if (province["code"] == code && province["name"] == name) {
selectProvince = province;
break;
}
}
List cityList = selectProvince["children"] ?? [];
return getTargetList(cityList);
} else if (index == 2) {
List cityList = selectProvince["children"] ?? [];
for (Map city in cityList) {
if (city["code"] == code && city["name"] == name) {
selectCity = city;
break;
}
}
List districtList = selectCity["children"] ?? [];
return getTargetList(districtList);
} else {
return [];
}
}
List<AddressNode> getTargetList(List<dynamic> list) {
return list
.map((item) => AddressNode(
name: item['name'],
code: item['code'],
letter: PinyinHelper.getFirstWordPinyin(item['name']).substring(0, 1).toUpperCase(),
))
.toList();
}
[@override](/user/override)
void onFinish(List<AddressNode> data) {
String newCity = "";
for (int i = 0; i < data.length; i++) {
if (i < data.length - 1) {
newCity += "${data[i].name},";
} else {
newCity += "${data[i].name}";
}
}
_addressArea = newCity;
_selectData = data;
setState(() {});
}
}
更多关于Flutter城市选择器插件luo_city_picker的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter城市选择器插件luo_city_picker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
luo_city_picker
是一个用于 Flutter 的城市选择器插件,允许用户从列表中选择省、市、区。它提供了一个简单易用的界面,适用于需要用户选择地址信息的应用程序。
安装
首先,你需要在 pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
luo_city_picker: ^版本号 # 请替换为最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
-
导入包
在你的 Dart 文件中导入
luo_city_picker
:import 'package:luo_city_picker/luo_city_picker.dart';
-
使用城市选择器
你可以通过调用
showCityPicker
方法来显示城市选择器。这个方法会返回一个Future
,用户选择城市后会返回选择的省、市、区信息。ElevatedButton( onPressed: () async { CityResult? result = await showCityPicker( context: context, ); if (result != null) { print("省: ${result.province}"); print("市: ${result.city}"); print("区: ${result.district}"); } }, child: Text('选择城市'), );
-
自定义配置
showCityPicker
方法允许你通过参数自定义选择器的行为。例如:CityResult? result = await showCityPicker( context: context, title: '请选择城市', // 标题 confirmText: '确定', // 确认按钮文本 cancelText: '取消', // 取消按钮文本 // 其他配置 );
返回值
showCityPicker
返回一个 CityResult
对象,包含以下属性:
province
: 选择的省city
: 选择的市district
: 选择的区
如果用户取消了选择,返回值为 null
。
示例代码
以下是一个完整的示例代码,展示如何使用 luo_city_picker
:
import 'package:flutter/material.dart';
import 'package:luo_city_picker/luo_city_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: CityPickerDemo(),
);
}
}
class CityPickerDemo extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('城市选择器示例'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
CityResult? result = await showCityPicker(
context: context,
title: '请选择城市',
confirmText: '确定',
cancelText: '取消',
);
if (result != null) {
print("省: ${result.province}");
print("市: ${result.city}");
print("区: ${result.district}");
}
},
child: Text('选择城市'),
),
),
);
}
}