//
// 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 初始化地理位置信息失敗, 請(qǐng)檢查省分城市數(shù)據(jù) \n $e');
}
requestPermission();
///設(shè)置Android和iOS的apiKey<br>
///key的申請(qǐng)請(qǐng)參考高德開放平臺(tái)官網(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();
// }
///注冊(cè)定位結(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ū)信息的情況
}
// 臺(tái)灣異常數(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;
}
/// 所有選項(xiàng)的點(diǎn)擊事件入口
/// @param targetPoint 被點(diǎn)擊對(duì)象的point對(duì)象
_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 = '請(qǐng)選擇城市';
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("未知定位類型");
}
}
/// 動(dòng)態(tài)申請(qǐng)定位權(quán)限
void requestPermission() async {
// 申請(qǐng)權(quán)限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
print("定位權(quán)限申請(qǐng)通過");
} else {
print("定位權(quán)限申請(qǐng)不通過");
}
}
/// 申請(qǐng)定位權(quán)限
/// 授予定位權(quán)限返回true, 否則返回false
Future<bool> requestLocationPermission() async {
//獲取當(dāng)前的權(quán)限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已經(jīng)授權(quán)
return true;
} else {
//未授權(quán)則發(fā)起一次申請(qǐng)
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;
///逆地理信息的語(yǔ)言類型
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)航場(chǎng)景的高精度 </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 標(biāo)題
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 點(diǎn)擊事件
onLongPress: () {},
// item onLongPress 長(zhǎng)按事件
selected: selectedId == item.code, // item 是否選中狀態(tài)
),
),
);
},
itemCount: itemList.length,
);
}
}
flutter
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- AppDelegate.m FlutterPlugin.h FlutterPlugin.m 最新微信SDK處理-u...
- 出現(xiàn)問題 Flutter 控制臺(tái)報(bào)錯(cuò) iOS Xcode 報(bào)錯(cuò)'Flutter/Flutter.h' file n...
- 老項(xiàng)目集成flutter的坑,報(bào)錯(cuò)如下(模擬器不報(bào)錯(cuò),真機(jī)報(bào)錯(cuò)): 網(wǎng)上說要將項(xiàng)目的bitcode關(guān)閉: 這個(gè)沒錯(cuò)...
- 看到Google出flutter_web的technical preview版本了。趕忙clone下來試了一下。 ...
- 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了,難過就哭了。兩者是相互影響密不可...