//
// 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();
}
// 界面狀態(tài)
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 初始化地理位置信息失敗, 請檢查省分城市數(shù)據(jù) \n $e');
}
requestPermission();
///設(shè)置Android和iOS的apiKey<br>
///key的申請請參考高德開放平臺官網(wǎng)說明<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();
// }
///注冊定位結(jié)果監(jiān)聽
_locationListener = _locationPlugin.onLocationChanged().listen((Map<String, Object> result) {
setState(() {
_locationResult = result;
});
// _locationResult['province'] +
// _locationResult['city'] +
// _locationResult['district'] +
// _locationResult['street'];
print("定位結(jié)果${_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');
// 此處兼容, 部分城市下無地區(qū)信息的情況
}
// 臺灣異常數(shù)據(jù). 需要過濾
// 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("未知定位類型");
}
}
/// 動態(tài)申請定位權(quán)限
void requestPermission() async {
// 申請權(quán)限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
print("定位權(quán)限申請通過");
} else {
print("定位權(quán)限申請不通過");
}
}
/// 申請定位權(quán)限
/// 授予定位權(quán)限返回true阔籽, 否則返回false
Future<bool> requestLocationPermission() async {
//獲取當前的權(quán)限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已經(jīng)授權(quán)
return true;
} else {
//未授權(quán)則發(fā)起一次申請
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
///設(shè)置定位參數(shù)
void _setLocationOption() {
AMapLocationOption locationOption = new AMapLocationOption();
///是否單次定位
locationOption.onceLocation = false;
///是否需要返回逆地理信息
locationOption.needAddress = true;
///逆地理信息的語言類型
locationOption.geoLanguage = GeoLanguage.DEFAULT;
locationOption.desiredLocationAccuracyAuthorizationMode =
AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
locationOption.fullAccuracyPurposeKey = "AMapLocationScene";
///設(shè)置Android端連續(xù)定位的定位間隔
locationOption.locationInterval = 2000;
///設(shè)置Android端的定位模式<br>
///可選值:<br>
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
///設(shè)置iOS端的定位最小更新距離<br>
locationOption.distanceFilter = -1;
///設(shè)置iOS端期望的定位精度
/// 可選值:<br>
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 適用于導(dǎo)航場景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
locationOption.desiredAccuracy = DesiredAccuracy.Best;
///設(shè)置iOS端是否允許系統(tǒng)暫停定位
locationOption.pausesLocationUpdatesAutomatically = false;
///將定位參數(shù)設(shè)置給定位插件
_locationPlugin.setLocationOption(locationOption);
}
///開始定位
void _startLocation() {
///開始定位之前設(shè)置定位參數(shù)
_setLocationOption();
_locationPlugin.startLocation();
// const timeout = const Duration(seconds: 5);
// Timer(timeout, () {
//callback function
_stopLocation(); // 5s之后
// });
}
///停止定位
void _stopLocation() {
_locationPlugin.stopLocation();
}
///
/// // @override
void dispose() {
super.dispose();
///移除定位監(jiān)聽
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 內(nèi)容內(nèi)邊距
enabled: true,
onTap: () {
onSelect(itemList[index]);
},
// item onTap 點擊事件
onLongPress: () {},
// item onLongPress 長按事件
selected: selectedId == item.code, // item 是否選中狀態(tài)
),
),
);
},
itemCount: itemList.length,
);
}
}
flutter
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門舶斧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人察皇,你說我怎么就攤上這事茴厉。” “怎么了什荣?”我有些...
- 文/不壞的土叔 我叫張陵矾缓,是天一觀的道長。 經(jīng)常有香客問我稻爬,道長嗜闻,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任桅锄,我火速辦了婚禮琉雳,結(jié)果婚禮上样眠,老公的妹妹穿的比我還像新娘。我一直安慰自己翠肘,他們只是感情好檐束,可當我...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著束倍,像睡著了一般被丧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肌幽,一...
- 文/蒼蘭香墨 我猛地睜開眼探入,長吁一口氣:“原來是場噩夢啊……” “哼狡孔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜂嗽,我...
- 正文 年R本政府宣布,位于F島的核電站宽档,受9級特大地震影響尉姨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雌贱,卻給世界環(huán)境...
- 文/蒙蒙 一啊送、第九天 我趴在偏房一處隱蔽的房頂上張望偿短。 院中可真熱鬧,春花似錦馋没、人聲如沸昔逗。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽勾怒。三九已至,卻和暖如春声旺,著一層夾襖步出監(jiān)牢的瞬間笔链,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- AppDelegate.m FlutterPlugin.h FlutterPlugin.m 最新微信SDK處理-u...
- 出現(xiàn)問題 Flutter 控制臺報錯 iOS Xcode 報錯'Flutter/Flutter.h' file n...
- 老項目集成flutter的坑,報錯如下(模擬器不報錯枪狂,真機報錯): 網(wǎng)上說要將項目的bitcode關(guān)閉: 這個沒錯...
- 看到Google出flutter_web的technical preview版本了危喉。趕忙clone下來試了一下。 ...
- 根據(jù)行數(shù)摘完,找到對應(yīng)Gradle文件報錯的那一行姥饰。 解決報錯。