//
// Created with Android Studio.
// User: 三帆
// Date: 10/02/2019
// Time: 21:52
// email: sanfan.hx@alibaba-inc.com
// tartget: xxx
//
import 'dart:async';
import 'dart:core';
import 'package:city_pickers/modal/base_citys.dart';
import 'package:city_pickers/modal/point.dart';
import 'package:city_pickers/modal/result.dart';
import 'package:city_pickers/src/show_types.dart';
import 'package:city_pickers/src/util.dart';
import 'package:flutter/material.dart';
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
import 'package:permission_handler/permission_handler.dart';
class FullPage extends StatefulWidget {
final String? locationCode;
final ShowType showType;
final Map<String, String> provincesData;
final Map<String, dynamic> citiesData;
FullPage({
this.locationCode,
required this.showType,
required this.provincesData,
required this.citiesData,
});
@override
_FullPageState createState() => _FullPageState();
}
// 界面状态
enum Status {
Province,
City,
Area,
Over,
}
class HistoryPageInfo {
Status status;
List<Point> itemList;
HistoryPageInfo({required this.status, required this.itemList});
}
class _FullPageState extends State<FullPage> {
/// list scroll control
late ScrollController scrollController;
/// provinces object [Point]
late List<Point> provinces;
/// cityTree modal ,for building tree that root is province
late CityTree cityTree;
/// page current statue, show p or a or c or over
late Status pageStatus;
/// show items maybe province city or area;
late List<Point> itemList;
/// body history, the max length is three
List<HistoryPageInfo> _history = [];
/// the target province user selected
late Point targetProvince;
/// the target city user selected
Point? targetCity;
/// the target area user selected
Point? targetArea;
@override
void initState() {
super.initState();
scrollController = new ScrollController();
provinces = new Provinces(metaInfo: widget.provincesData).provinces;
cityTree = new CityTree(
metaInfo: widget.citiesData, provincesInfo: widget.provincesData);
itemList = provinces;
pageStatus = Status.Province;
try {
_initLocation(widget.locationCode);
} catch (e) {
print('Exception details:\n 初始化地理位置信息失败, 请检查省分城市数据 \n $e');
}
requestPermission();
///设置Android和iOS的apiKey<br>
///key的申请请参考高德开放平台官网说明<br>
///Android: https://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key
///iOS: https://lbs.amap.com/api/ios-location-sdk/guide/create-project/get-key
// AMapFlutterLocation.setApiKey("f710757e921fdcdb74b7fc29695c589d", "f710757e921fdcdb74b7fc29695c589d");
///iOS 获取native精度类型
// if (Platform.isIOS) {
// requestAccuracyAuthorization();
// }
///注册定位结果监听
_locationListener = _locationPlugin.onLocationChanged().listen((Map<String, Object> result) {
setState(() {
_locationResult = result;
});
// _locationResult['province'] +
// _locationResult['city'] +
// _locationResult['district'] +
// _locationResult['street'];
print("定位结果${_locationResult['city']}");
});
}
Future<bool> back() {
HistoryPageInfo? last = _history.length > 0 ? _history.last : null;
if (last != null && mounted) {
this.setState(() {
pageStatus = last.status;
itemList = last.itemList;
});
_history.removeLast();
return Future<bool>.value(false);
}
return Future<bool>.value(true);
}
void _initLocation(String? locationCode) {
int _locationCode;
if (locationCode != null) {
try {
_locationCode = int.parse(locationCode);
} catch (e) {
print(ArgumentError(
"The Argument locationCode must be valid like: '100000' but get '$locationCode' "));
return;
}
targetProvince = cityTree.initTreeByCode(_locationCode);
if (targetProvince.isNull) {
targetProvince = cityTree.initTreeByCode(provinces.first.code!);
}
targetProvince.child.forEach((Point _city) {
if (_city.code == _locationCode) {
targetCity = _city;
targetArea = _getTargetChildFirst(_city) ?? null;
}
_city.child.forEach((Point _area) {
if (_area.code == _locationCode) {
targetCity = _city;
targetArea = _area;
}
});
});
} else {
targetProvince =
cityTree.initTreeByCode(int.parse(widget.provincesData.keys.first));
}
if (targetCity == null) {
targetCity = _getTargetChildFirst(targetProvince);
}
if (targetArea == null) {
targetArea = _getTargetChildFirst(targetCity!);
}
}
Result _buildResult() {
Result result = Result();
ShowType showType = widget.showType;
try {
if (showType.contain(ShowType.p)) {
result.provinceId = targetProvince.code.toString();
result.provinceName = targetProvince.name;
}
if (showType.contain(ShowType.c)) {
result.provinceId = targetProvince.code.toString();
result.provinceName = targetProvince.name;
result.cityId = targetCity?.code.toString();
result.cityName = targetCity?.name;
}
if (showType.contain(ShowType.a)) {
result.provinceId = targetProvince.code.toString();
result.provinceName = targetProvince.name;
result.cityId = targetCity?.code.toString();
result.cityName = targetCity?.name;
result.areaId = targetArea?.code.toString();
result.areaName = targetArea?.name;
}
} catch (e) {
print('Exception details:\n _buildResult error \n $e');
// 此处兼容, 部分城市下无地区信息的情况
}
// 台湾异常数据. 需要过滤
// if (result.provinceId == "710000") {
// result.cityId = null;
// result.cityName = null;
// result.areaId = null;
// result.areaName = null;
// }
return result;
}
Point? _getTargetChildFirst(Point target) {
if (target == null) {
return null;
}
if (target.child != null && target.child.isNotEmpty) {
return target.child.first;
}
return null;
}
popHome() {
Navigator.of(context).pop(_buildResult());
}
_onProvinceSelect(Point province) {
this.setState(() {
targetProvince = cityTree.initTree(province.code!);
});
}
_onAreaSelect(Point area) {
this.setState(() {
targetArea = area;
});
}
_onCitySelect(Point city) {
this.setState(() {
targetCity = city;
});
}
int _getSelectedId() {
int? selectId;
switch (pageStatus) {
case Status.Province:
selectId = targetProvince.code;
break;
case Status.City:
selectId = targetCity?.code;
break;
case Status.Area:
selectId = targetArea?.code;
break;
case Status.Over:
break;
}
return selectId ?? 0;
}
/// 所有选项的点击事件入口
/// @param targetPoint 被点击对象的point对象
_onItemSelect(Point targetPoint) {
_history.add(HistoryPageInfo(itemList: itemList, status: pageStatus));
print(this.isSelected.toString());
Status nextStatus = Status.Over;
List<Point>? nextItemList;
switch (pageStatus) {
case Status.Province:
_onProvinceSelect(targetPoint);
nextStatus = Status.City;
nextItemList = targetProvince.child;
if (!widget.showType.contain(ShowType.c)) {
nextStatus = Status.Over;
}
if (nextItemList.isEmpty) {
targetCity = null;
targetArea = null;
nextStatus = Status.Over;
}
break;
case Status.City:
_onCitySelect(targetPoint);
nextStatus = Status.Area;
nextItemList = targetCity?.child;
if (!widget.showType.contain(ShowType.a)) {
nextStatus = Status.Over;
}
if (nextItemList == null || nextItemList.isEmpty) {
targetArea = null;
nextStatus = Status.Over;
}
break;
case Status.Area:
nextStatus = Status.Over;
_onAreaSelect(targetPoint);
break;
case Status.Over:
break;
}
setTimeout(
milliseconds: 300,
callback: () {
if (nextItemList == null || nextStatus == Status.Over) {
return popHome();
}
if (mounted) {
this.setState(() {
itemList = nextItemList!;
pageStatus = nextStatus;
});
scrollController.jumpTo(0.0);
}
});
}
Widget _buildHead() {
String title = '请选择城市';
switch (pageStatus) {
case Status.Province:
this.isSelected = false;
break;
case Status.City:
title = targetProvince.name;
this.isSelected = true;
break;
case Status.Area:
title = targetCity!.name;
this.isSelected = true;
break;
case Status.Over:
break;
}
return Text(title);
}
List cityList = ["北京", "杭州", "宁波", "温州", "上海", "深圳"];
bool isSelected = false;
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: back,
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: _buildHead(),
),
body: SafeArea(
bottom: true,
child:
// ListWidget(
// itemList: itemList,
// controller: scrollController,
// onSelect: _onItemSelect,
// selectedId: _getSelectedId(),
// ),
ListView(
children: [
Offstage(
offstage: isSelected,
child: Column(
children: [
Container(
height: 50, child:Text('${_locationResult==null?"重新定位":_locationResult['city']}')
// LocationNamePage()
// Text("重新定位"),
),
Container(
height: 100,
// decoration: new BoxDecoration(
// border: new Border.all(color: Colors.grey,
// width: 0.5),),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
childAspectRatio:3,
mainAxisSpacing:10
),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
alignment: Alignment.center,
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.grey, width: 0.5),),
height: 8,
child: Text("${cityList[index]}"),
);
},
itemCount: 6,
),
),
],
)
),
Container(
child:
ListWidget(
itemList: itemList,
controller: scrollController,
onSelect: _onItemSelect,
selectedId: _getSelectedId(),
),
)
],
)
),
),
);
}
///定位
Map<String, Object> _locationResult= new Map();
AMapFlutterLocation _locationPlugin = new AMapFlutterLocation();
StreamSubscription<Map<String, Object>> _locationListener = new StreamSubscription();
///获取iOS native的accuracyAuthorization类型
void requestAccuracyAuthorization() async {
AMapAccuracyAuthorization currentAccuracyAuthorization =
await _locationPlugin.getSystemAccuracyAuthorization();
if (currentAccuracyAuthorization ==
AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
print("精确定位类型");
} else if (currentAccuracyAuthorization ==
AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
print("模糊定位类型");
} else {
print("未知定位类型");
}
}
/// 动态申请定位权限
void requestPermission() async {
// 申请权限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
print("定位权限申请通过");
} else {
print("定位权限申请不通过");
}
}
/// 申请定位权限
/// 授予定位权限返回true, 否则返回false
Future<bool> requestLocationPermission() async {
//获取当前的权限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已经授权
return true;
} else {
//未授权则发起一次申请
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
///设置定位参数
void _setLocationOption() {
AMapLocationOption locationOption = new AMapLocationOption();
///是否单次定位
locationOption.onceLocation = false;
///是否需要返回逆地理信息
locationOption.needAddress = true;
///逆地理信息的语言类型
locationOption.geoLanguage = GeoLanguage.DEFAULT;
locationOption.desiredLocationAccuracyAuthorizationMode =
AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
locationOption.fullAccuracyPurposeKey = "AMapLocationScene";
///设置Android端连续定位的定位间隔
locationOption.locationInterval = 2000;
///设置Android端的定位模式<br>
///可选值:<br>
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
///设置iOS端的定位最小更新距离<br>
locationOption.distanceFilter = -1;
///设置iOS端期望的定位精度
/// 可选值:<br>
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
locationOption.desiredAccuracy = DesiredAccuracy.Best;
///设置iOS端是否允许系统暂停定位
locationOption.pausesLocationUpdatesAutomatically = false;
///将定位参数设置给定位插件
_locationPlugin.setLocationOption(locationOption);
}
///开始定位
void _startLocation() {
///开始定位之前设置定位参数
_setLocationOption();
_locationPlugin.startLocation();
// const timeout = const Duration(seconds: 5);
// Timer(timeout, () {
//callback function
_stopLocation(); // 5s之后
// });
}
///停止定位
void _stopLocation() {
_locationPlugin.stopLocation();
}
///
/// // @override
void dispose() {
super.dispose();
///移除定位监听
if (null != _locationListener) {
_locationListener.cancel();
}
///销毁定位
_locationPlugin.destroy();
}
}
class ListWidget extends StatelessWidget {
final List<Point> itemList;
final ScrollController controller;
final int selectedId;
final ValueChanged<Point> onSelect;
ListWidget({required this.itemList,
required this.onSelect,
required this.controller,
required this.selectedId});
@override
Widget build(BuildContext context) {
ThemeData theme = Theme.of(context);
return ListView.builder(
controller: controller,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
Point item = itemList[index];
return Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: theme.dividerColor, width: 1.0))),
child: ListTileTheme(
child: ListTile(
title: Text(item.name),
// item 标题
dense: true,
// item 直观感受是整体大小
trailing: selectedId == item.code
? Icon(Icons.check, color: theme.primaryColor)
: null,
contentPadding: EdgeInsets.fromLTRB(24.0, .0, 24.0, 3.0),
// item 内容内边距
enabled: true,
onTap: () {
onSelect(itemList[index]);
},
// item onTap 点击事件
onLongPress: () {},
// item onLongPress 长按事件
selected: selectedId == item.code, // item 是否选中状态
),
),
);
},
itemCount: itemList.length,
);
}
}
flutter
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- AppDelegate.m FlutterPlugin.h FlutterPlugin.m 最新微信SDK处理-u...
- 出现问题 Flutter 控制台报错 iOS Xcode 报错'Flutter/Flutter.h' file n...
- 老项目集成flutter的坑,报错如下(模拟器不报错,真机报错): 网上说要将项目的bitcode关闭: 这个没错...
- 看到Google出flutter_web的technical preview版本了。赶忙clone下来试了一下。 ...
- 根据行数,找到对应Gradle文件报错的那一行。 解决报错。