amap_map_fluttify
This commit is contained in:
501
example/lib/map/create_map/create_map.screen.dart
Normal file
501
example/lib/map/create_map/create_map.screen.dart
Normal file
@ -0,0 +1,501 @@
|
||||
import 'dart:math';
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:vector_math/vector_math.dart' as vector;
|
||||
|
||||
final _assetsIcon = AssetImage('images/test_icon.png');
|
||||
|
||||
class CreateMapScreen extends StatefulWidget {
|
||||
@override
|
||||
_CreateMapScreenState createState() => _CreateMapScreenState();
|
||||
}
|
||||
|
||||
class _CreateMapScreenState extends State<CreateMapScreen>
|
||||
with NextLatLng, DisposeBag {
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('自定义地图')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: DecoratedStack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
AmapView(
|
||||
showZoomControl: false,
|
||||
tilt: 60,
|
||||
zoomLevel: 17,
|
||||
centerCoordinate: LatLng(29, 119),
|
||||
maskDelay: Duration(milliseconds: 500),
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
// Image.asset('images/test_icon.png'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
// BooleanSetting(
|
||||
// head: '是否显示定位',
|
||||
// onSelected: (value) async {
|
||||
// await Permission.location.request();
|
||||
// await _controller
|
||||
// ?.showMyLocation(MyLocationOption(show: value));
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '选择定位模式',
|
||||
// options: <String>[
|
||||
// '只定位不移动地图到中心',
|
||||
// '定位一次并移动地图到中心',
|
||||
// '连续定位并跟随',
|
||||
// '跟随但不移动到地图中心',
|
||||
// '连续定位跟随方向',
|
||||
// ],
|
||||
// onSelected: (String value) async {
|
||||
// if (value == '只定位不移动地图到中心') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Show,
|
||||
// ));
|
||||
// } else if (value == '定位一次并移动地图到中心') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Locate,
|
||||
// ));
|
||||
// } else if (value == '连续定位并跟随') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Follow,
|
||||
// interval: Duration(seconds: 3),
|
||||
// ));
|
||||
// } else if (value == '跟随但不移动到地图中心') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.FollowNoCenter,
|
||||
// ));
|
||||
// } else if (value == '连续定位跟随方向') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Rotate,
|
||||
// ));
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '选择定位间隔时间',
|
||||
// options: <String>[
|
||||
// '1秒',
|
||||
// '3秒',
|
||||
// '5秒',
|
||||
// ],
|
||||
// onSelected: (String value) async {
|
||||
// if (value == '1秒') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Follow,
|
||||
// interval: Duration(seconds: 1),
|
||||
// ));
|
||||
// } else if (value == '3秒') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Follow,
|
||||
// interval: Duration(seconds: 3),
|
||||
// ));
|
||||
// } else if (value == '5秒') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Follow,
|
||||
// interval: Duration(seconds: 5),
|
||||
// ));
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取当前位置经纬度')),
|
||||
onTap: () async {
|
||||
final latLng = await _controller.getLocation();
|
||||
toast('当前经纬度: ${latLng?.latitude}, ${latLng?.longitude}');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('旋转定位图标')),
|
||||
onTap: () async {
|
||||
await _controller.setMyLocationRotateAngle(90);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('使用自定义定位图标')),
|
||||
onTap: () async {
|
||||
await _controller.showMyLocation(
|
||||
MyLocationOption(iconProvider: _assetsIcon));
|
||||
},
|
||||
),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示室内地图',
|
||||
// onSelected: (value) {
|
||||
// _controller.showIndoorMap(value);
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '切换地图图层',
|
||||
// options: ['正常视图', '卫星视图', '黑夜视图', '导航视图', '公交视图'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '正常视图':
|
||||
// _controller.setMapType(MapType.Standard);
|
||||
// break;
|
||||
// case '卫星视图':
|
||||
// _controller.setMapType(MapType.Satellite);
|
||||
// break;
|
||||
// case '黑夜视图':
|
||||
// _controller.setMapType(MapType.Night);
|
||||
// break;
|
||||
// case '导航视图':
|
||||
// _controller.setMapType(MapType.Navi);
|
||||
// break;
|
||||
// case '公交视图':
|
||||
// _controller.setMapType(MapType.Bus);
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '切换语言',
|
||||
// options: ['中文', '英文'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '中文':
|
||||
// _controller.setMapLanguage(Language.Chinese);
|
||||
// break;
|
||||
// case '英文':
|
||||
// _controller.setMapLanguage(Language.English);
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈边框颜色',
|
||||
// options: ['红色', '绿色', '蓝色'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '红色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.red,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '绿色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.green,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '蓝色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.blue,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈填充颜色',
|
||||
// options: ['红色', '绿色', '蓝色'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '红色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.red,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '绿色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.green,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '蓝色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.blue,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈边框宽度',
|
||||
// options: ['2', '4', '8'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '2':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '4':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 4,
|
||||
// ));
|
||||
// break;
|
||||
// case '8':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 8,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示路况信息',
|
||||
// onSelected: (value) {
|
||||
// _controller.showTraffic(value);
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取地图中心点')),
|
||||
onTap: () async {
|
||||
final center = await _controller.getCenterCoordinate();
|
||||
|
||||
print('center: lat: ${center.latitude}, lng: ${center.longitude}');
|
||||
// toast(
|
||||
// 'center: lat: ${center.latitude}, lng: ${center.longitude}');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('监听地图移动')),
|
||||
onTap: () {
|
||||
_controller.setMapMoveListener(
|
||||
onMapMoveStart: (move) async => debugPrint('开始移动: $move'),
|
||||
onMapMoving: (move) async => debugPrint('移动中: $move'),
|
||||
onMapMoveEnd: (move) async => debugPrint('结束移动: $move'),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加点击地图监听')),
|
||||
onTap: () {
|
||||
_controller.setMapClickedListener(
|
||||
(latLng) async {
|
||||
toast(
|
||||
'点击: lat: ${latLng.latitude}, lng: ${latLng.longitude}',
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('自定义地图')),
|
||||
onTap: () {
|
||||
_controller.setCustomMapStyle(
|
||||
styleDataPath: 'raw/style.data',
|
||||
styleExtraPath: 'raw/style_extra.data',
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('经纬度坐标转屏幕坐标')),
|
||||
onTap: () async {
|
||||
final centerLatLng =
|
||||
await _controller.getCenterCoordinate();
|
||||
final screenPoint =
|
||||
await _controller.toScreenLocation(centerLatLng);
|
||||
toast('地图中心点对应的屏幕坐标为: $screenPoint');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('屏幕坐标转经纬度坐标')),
|
||||
onTap: () async {
|
||||
final screenPoint = Point(250, 250);
|
||||
final latLng =
|
||||
await _controller.fromScreenLocation(screenPoint);
|
||||
toast('屏幕坐标(250, 250)对应的经纬度坐标为: $latLng');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('设置屏幕上的某个像素点为地图中心点')),
|
||||
onTap: () async {
|
||||
final screenPoint = Point(20, 20);
|
||||
// await _controller.setPointToCenter(screenPoint);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('设置以地图为中心进行缩放')),
|
||||
onTap: () async {
|
||||
await _controller.setZoomByCenter(true);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('限制地图显示范围')),
|
||||
onTap: () async {
|
||||
final southWest = LatLng(40, 116);
|
||||
final northEast = LatLng(42, 118);
|
||||
await _controller.setMapRegionLimits(southWest, northEast);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取当前缩放等级')),
|
||||
onTap: () async {
|
||||
toast('当前缩放等级: ${await _controller.getZoomLevel()}');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('(专业版)一次性设置地图状态')),
|
||||
onTap: () async {
|
||||
final point = getNextLatLng();
|
||||
await _controller.setCameraPosition(
|
||||
coordinate: point,
|
||||
zoom: 12,
|
||||
tilt: 90,
|
||||
bearing: 339.000732421875,
|
||||
duration: Duration(seconds: 2),
|
||||
);
|
||||
await Future.delayed(Duration(seconds: 3));
|
||||
await _controller.setCameraPosition(
|
||||
coordinate: point,
|
||||
zoom: 12,
|
||||
tilt: 90,
|
||||
bearing: 400.86966387385837,
|
||||
duration: Duration(seconds: 2),
|
||||
);
|
||||
// await Future.delayed(Duration(seconds: 3));
|
||||
// await _controller.setCameraPosition(
|
||||
// coordinate: point,
|
||||
// zoom: 12,
|
||||
// tilt: 90,
|
||||
// bearing: 41,
|
||||
// duration: Duration(seconds: 2),
|
||||
// );
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('(专业版)设置地图锚点')),
|
||||
onTap: () {
|
||||
_controller.setMapAnchor(0.8, 0.8);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('测试')),
|
||||
onTap: () {
|
||||
context.navigator.push(MaterialPageRoute(
|
||||
builder: (context) => _SecondScreen()));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('根据朝向旋转定位图标')),
|
||||
onTap: () {
|
||||
AmapLocation.instance
|
||||
.listenLocation()
|
||||
.listen((it) =>
|
||||
_controller.setMyLocationRotateAngle(it.bearing!))
|
||||
.addTo(disposeBag);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('行程动画')),
|
||||
onTap: () async {
|
||||
final result = await AmapSearch.instance.searchDriveRoute(
|
||||
from: LatLng(39.958245, 116.330929),
|
||||
to: LatLng(39.915599, 116.42912),
|
||||
);
|
||||
final pathList = await result.drivePathList;
|
||||
final stepList = [
|
||||
for (final path in pathList) ...await path.driveStepList
|
||||
];
|
||||
final coordinateList = [
|
||||
for (final step in stepList) ...await step.polyline
|
||||
];
|
||||
await _controller.addPlaybackTrace(
|
||||
coordinateList,
|
||||
iconProvider: _assetsIcon,
|
||||
duration: Duration(
|
||||
milliseconds: coordinateList.length * 500,
|
||||
),
|
||||
);
|
||||
for (int i = 0; i < coordinateList.length; i++) {
|
||||
final last = coordinateList[max(i - 1, 0)];
|
||||
final current = coordinateList[i];
|
||||
await _controller.setCameraPosition(
|
||||
coordinate: coordinateList[i],
|
||||
zoom: 18,
|
||||
tilt: 45,
|
||||
bearing: bearing(
|
||||
last.latitude,
|
||||
last.longitude,
|
||||
current.latitude,
|
||||
current.longitude,
|
||||
) -
|
||||
105,
|
||||
);
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double bearing(double lat1, double lon1, double lat2, double lon2) {
|
||||
double longitude1 = lon1;
|
||||
double longitude2 = lon2;
|
||||
double latitude1 = vector.radians(lat1);
|
||||
double latitude2 = vector.radians(lat2);
|
||||
double longDiff = vector.radians(longitude2 - longitude1);
|
||||
double y = sin(longDiff) * cos(latitude2);
|
||||
double x = cos(latitude1) * sin(latitude2) -
|
||||
sin(latitude1) * cos(latitude2) * cos(longDiff);
|
||||
return (vector.degrees((atan2(y, x)) + 360) % 360);
|
||||
}
|
||||
|
||||
double getAngle(double lng1, double lat1, double lng2, double lat2) {
|
||||
double dRotateAngle = atan2((lng2 - lng1).abs(), (lat2 - lat1).abs());
|
||||
if (lng2 >= lng1) {
|
||||
if (lat2 > lat1) {
|
||||
dRotateAngle = 2 * pi - dRotateAngle;
|
||||
}
|
||||
} else {
|
||||
if (lat2 >= lat1) {
|
||||
dRotateAngle = pi + dRotateAngle;
|
||||
} else {
|
||||
dRotateAngle = pi - dRotateAngle;
|
||||
}
|
||||
}
|
||||
dRotateAngle = dRotateAngle * 180 / pi;
|
||||
return dRotateAngle;
|
||||
}
|
||||
}
|
||||
|
||||
class _SecondScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedColumn(
|
||||
children: [
|
||||
Flexible(child: AmapView()),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapLocation.instance.listenLocation().listen((event) {
|
||||
print(event);
|
||||
});
|
||||
},
|
||||
child: Text('开始定位'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapLocation.instance.stopLocation();
|
||||
},
|
||||
child: Text('停止定位'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
332
example/lib/map/create_map/multi_map.screen.dart
Normal file
332
example/lib/map/create_map/multi_map.screen.dart
Normal file
@ -0,0 +1,332 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final _assetsIcon = AssetImage('images/test_icon.png');
|
||||
|
||||
class MultiMapScreen extends StatefulWidget {
|
||||
@override
|
||||
_MultiMapScreenState createState() => _MultiMapScreenState();
|
||||
}
|
||||
|
||||
class _MultiMapScreenState extends State<MultiMapScreen> {
|
||||
late AmapController _controller1;
|
||||
late AmapController _controller2;
|
||||
late AmapController _controller;
|
||||
String _currentInstance = '地图1';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('自定义地图')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: AmapView(
|
||||
key: Key('map1'),
|
||||
showZoomControl: false,
|
||||
maskDelay: Duration(milliseconds: 500),
|
||||
onMapCreated: (controller) async {
|
||||
_controller1 = controller;
|
||||
_controller = _controller1;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: AmapView(
|
||||
key: Key('map2'),
|
||||
showZoomControl: false,
|
||||
maskDelay: Duration(milliseconds: 500),
|
||||
onMapCreated: (controller) async {
|
||||
_controller2 = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
// DiscreteSetting(
|
||||
// head: '选择地图实例 当前实例: $_currentInstance',
|
||||
// options: <String>['地图1', '地图2'],
|
||||
// onSelected: (String value) {
|
||||
// switch (value) {
|
||||
// case '地图1':
|
||||
// setState(() {
|
||||
// _currentInstance = '地图1';
|
||||
// _controller = _controller1;
|
||||
// });
|
||||
// break;
|
||||
// case '地图2':
|
||||
// setState(() {
|
||||
// _currentInstance = '地图2';
|
||||
// _controller = _controller2;
|
||||
// });
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示定位',
|
||||
// onSelected: (value) async {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// show: value,
|
||||
// ));
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '选择定位模式',
|
||||
// options: <String>[
|
||||
// '只定位不移动地图到中心',
|
||||
// '定位一次并移动地图到中心',
|
||||
// '连续定位并跟随',
|
||||
// '连续定位跟随方向',
|
||||
// ],
|
||||
// onSelected: (String value) async {
|
||||
// if (value == '只定位不移动地图到中心') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Show,
|
||||
// ));
|
||||
// } else if (value == '定位一次并移动地图到中心') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Locate,
|
||||
// ));
|
||||
// } else if (value == '连续定位并跟随') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Follow,
|
||||
// ));
|
||||
// } else if (value == '连续定位跟随方向') {
|
||||
// await _controller.showMyLocation(MyLocationOption(
|
||||
// myLocationType: MyLocationType.Rotate,
|
||||
// ));
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取当前位置经纬度')),
|
||||
onTap: () async {
|
||||
final latLng = await _controller.getLocation();
|
||||
toast('当前经纬度: ${latLng.toString()}');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('使用自定义定位图标')),
|
||||
onTap: () async {
|
||||
await _controller.showMyLocation(MyLocationOption(
|
||||
myLocationType: MyLocationType.Rotate,
|
||||
iconProvider: _assetsIcon,
|
||||
));
|
||||
},
|
||||
),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示室内地图',
|
||||
// onSelected: (value) {
|
||||
// _controller.showIndoorMap(value);
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '切换地图图层',
|
||||
// options: ['正常视图', '卫星视图', '黑夜视图', '导航视图', '公交视图'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '正常视图':
|
||||
// _controller.setMapType(MapType.Standard);
|
||||
// break;
|
||||
// case '卫星视图':
|
||||
// _controller.setMapType(MapType.Satellite);
|
||||
// break;
|
||||
// case '黑夜视图':
|
||||
// _controller.setMapType(MapType.Night);
|
||||
// break;
|
||||
// case '导航视图':
|
||||
// _controller.setMapType(MapType.Navi);
|
||||
// break;
|
||||
// case '公交视图':
|
||||
// _controller.setMapType(MapType.Bus);
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '切换语言',
|
||||
// options: ['中文', '英文'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '中文':
|
||||
// _controller.setMapLanguage(Language.Chinese);
|
||||
// break;
|
||||
// case '英文':
|
||||
// _controller.setMapLanguage(Language.English);
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈边框颜色',
|
||||
// options: ['红色', '绿色', '蓝色'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '红色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.red,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '绿色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.green,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '蓝色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeColor: Colors.blue,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈填充颜色',
|
||||
// options: ['红色', '绿色', '蓝色'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '红色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.red,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '绿色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.green,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '蓝色':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// fillColor: Colors.blue,
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '精度圈边框宽度',
|
||||
// options: ['2', '4', '8'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '2':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 2,
|
||||
// ));
|
||||
// break;
|
||||
// case '4':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 4,
|
||||
// ));
|
||||
// break;
|
||||
// case '8':
|
||||
// _controller.showMyLocation(MyLocationOption(
|
||||
// strokeWidth: 8,
|
||||
// ));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示路况信息',
|
||||
// onSelected: (value) {
|
||||
// _controller.showTraffic(value);
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取地图中心点')),
|
||||
onTap: () async {
|
||||
final center = await _controller.getCenterCoordinate();
|
||||
toast(
|
||||
'center: lat: ${center.latitude}, lng: ${center.longitude}');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('监听地图移动')),
|
||||
onTap: () {
|
||||
_controller.setMapMoveListener(
|
||||
onMapMoveStart: (move) async => toast('开始移动: $move'),
|
||||
onMapMoveEnd: (move) async => toast('结束移动: $move'),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加点击地图监听')),
|
||||
onTap: () {
|
||||
_controller.setMapClickedListener(
|
||||
(latLng) async {
|
||||
toast(
|
||||
'点击: lat: ${latLng.latitude}, lng: ${latLng.longitude}',
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('自定义地图')),
|
||||
onTap: () {
|
||||
_controller.setCustomMapStyle(
|
||||
styleDataPath: 'raw/style.data',
|
||||
styleExtraPath: 'raw/style_extra.data',
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('经纬度坐标转屏幕坐标')),
|
||||
onTap: () async {
|
||||
final centerLatLng =
|
||||
await _controller.getCenterCoordinate();
|
||||
final screenPoint =
|
||||
await _controller.toScreenLocation(centerLatLng);
|
||||
toast('地图中心点对应的屏幕坐标为: $screenPoint');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('屏幕坐标转经纬度坐标')),
|
||||
onTap: () async {
|
||||
final screenPoint = Point(250, 250);
|
||||
final latLng =
|
||||
await _controller.fromScreenLocation(screenPoint);
|
||||
toast('屏幕坐标(250, 250)对应的经纬度坐标为: $latLng');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('设置以地图为中心进行缩放')),
|
||||
onTap: () async {
|
||||
await _controller.setZoomByCenter(true);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('限制地图显示范围')),
|
||||
onTap: () async {
|
||||
final southWest = LatLng(40, 116);
|
||||
final northEast = LatLng(42, 118);
|
||||
await _controller.setMapRegionLimits(southWest, northEast);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('获取当前缩放等级')),
|
||||
onTap: () async {
|
||||
toast('当前缩放等级: ${await _controller.getZoomLevel()}');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
65
example/lib/map/draw_on_map/draw_circle.screen.dart
Normal file
65
example/lib/map/draw_on_map/draw_circle.screen.dart
Normal file
@ -0,0 +1,65 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DrawCircleScreen extends StatefulWidget {
|
||||
DrawCircleScreen();
|
||||
|
||||
factory DrawCircleScreen.forDesignTime() => DrawCircleScreen();
|
||||
|
||||
@override
|
||||
_DrawCircleScreenState createState() => _DrawCircleScreenState();
|
||||
}
|
||||
|
||||
class _DrawCircleScreenState extends State<DrawCircleScreen> with NextLatLng {
|
||||
late AmapController _controller;
|
||||
List<ICircle> _circleList = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('绘制圆')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Center(child: Text('添加圆')),
|
||||
onTap: () async {
|
||||
final circle = await _controller.addCircle(CircleOption(
|
||||
center: LatLng(39.999391, 116.135972),
|
||||
radius: 10000,
|
||||
width: 10,
|
||||
strokeColor: Colors.green,
|
||||
));
|
||||
_circleList.add(circle);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除圆')),
|
||||
onTap: () async {
|
||||
if (_circleList.isNotEmpty) {
|
||||
await _circleList.first.remove();
|
||||
_circleList.removeAt(0);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
67
example/lib/map/draw_on_map/draw_ground_overlay.screen.dart
Normal file
67
example/lib/map/draw_on_map/draw_ground_overlay.screen.dart
Normal file
@ -0,0 +1,67 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final _networkIcon = NetworkImage(
|
||||
'https://w3.hoopchina.com.cn/30/a7/6a/30a76aea75aef69e4ea0e7d3dee552c7001.jpg');
|
||||
final _assetsIcon1 = AssetImage('images/test_icon.png');
|
||||
final _assetsIcon2 = AssetImage('images/arrow.png');
|
||||
|
||||
class DrawGroundOverlayScreen extends StatefulWidget {
|
||||
DrawGroundOverlayScreen();
|
||||
|
||||
@override
|
||||
DrawGroundOverlayScreenState createState() => DrawGroundOverlayScreenState();
|
||||
}
|
||||
|
||||
class DrawGroundOverlayScreenState extends State<DrawGroundOverlayScreen>
|
||||
with NextLatLng {
|
||||
late AmapController _controller;
|
||||
late IGroundOverlay _overlay;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('绘制点标记')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Center(child: Text('添加图片覆盖物')),
|
||||
onTap: () async {
|
||||
_overlay = await _controller.addGroundOverlay(
|
||||
GroundOverlayOption(
|
||||
northEast: LatLng(40.047815, 116.5742),
|
||||
imageProvider: _assetsIcon1,
|
||||
southWest: LatLng(39.836183, 116.218517),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除图片覆盖物')),
|
||||
onTap: () {
|
||||
_overlay.remove();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
537
example/lib/map/draw_on_map/draw_point.screen.dart
Normal file
537
example/lib/map/draw_on_map/draw_point.screen.dart
Normal file
@ -0,0 +1,537 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/misc.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final _networkIcon = NetworkImage(
|
||||
'https://w3.hoopchina.com.cn/30/a7/6a/30a76aea75aef69e4ea0e7d3dee552c7001.jpg');
|
||||
final _assetsIcon1 = AssetImage('images/test_icon.png');
|
||||
final _assetsIcon2 = AssetImage('images/arrow.png');
|
||||
|
||||
class DrawPointScreen extends StatefulWidget {
|
||||
DrawPointScreen();
|
||||
|
||||
@override
|
||||
DrawPointScreenState createState() => DrawPointScreenState();
|
||||
}
|
||||
|
||||
class DrawPointScreenState extends State<DrawPointScreen> with NextLatLng {
|
||||
late AmapController _controller;
|
||||
List<IMarker> _markers = [];
|
||||
late IMarker _hiddenMarker;
|
||||
late ISmoothMoveMarker _moveMarker;
|
||||
late IMultiPointOverlay _multiPointOverlay;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('绘制点标记')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
zoomLevel: 6,
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
// await _controller.setMapAnchor(0.5, 0.8);
|
||||
if (await requestPermission()) {
|
||||
await controller.setZoomLevel(6);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Center(child: Text('添加Widget Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarkers(
|
||||
[
|
||||
for (int i = 0; i < 10; i++)
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
widget: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text('使用Widget作为Marker: $i'),
|
||||
Image.asset('images/test_icon.png'),
|
||||
],
|
||||
),
|
||||
title: '北京',
|
||||
snippet: '描述',
|
||||
)
|
||||
],
|
||||
);
|
||||
_markers.addAll(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
title: '北京${random.nextDouble()}',
|
||||
snippet: '描述${random.nextDouble()}',
|
||||
infoWindowEnabled: true,
|
||||
draggable: true,
|
||||
object: '自定义数据${random.nextDouble()}',
|
||||
opacity: 0.7,
|
||||
),
|
||||
);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('旋转Marker')),
|
||||
onTap: () {
|
||||
_markers.firstOrNull?.setAngle(90);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加自定义Info Window')),
|
||||
onTap: () async {
|
||||
// await _controller.setMarkerClickedListener((marker) async {
|
||||
// await _controller.showCustomInfoWindow(
|
||||
// marker,
|
||||
// Card(
|
||||
// elevation: 10,
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.all(16),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Icon(Icons.location_on),
|
||||
// Text(await marker.title),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// });
|
||||
// info window点击事件
|
||||
|
||||
|
||||
|
||||
|
||||
await _controller
|
||||
.setInfoWindowClickListener((marker) async {
|
||||
toast(await marker.title);
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加自定义图片Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
title: '北京${random.nextDouble()}',
|
||||
snippet: '描述${random.nextDouble()}',
|
||||
iconProvider: _assetsIcon1,
|
||||
infoWindowEnabled: true,
|
||||
object: '自定义数据${random.nextDouble()}',
|
||||
),
|
||||
);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加缩放动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider: _assetsIcon1,
|
||||
anchorU: 0.5,
|
||||
anchorV: 1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
await marker.startAnimation(ScaleMarkerAnimation(
|
||||
fromValue: 0.8,
|
||||
toValue: 1.2,
|
||||
duration: Duration(milliseconds: 1000),
|
||||
repeatCount: 0,
|
||||
));
|
||||
await marker.setVisible(true);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加移动动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider: _assetsIcon1,
|
||||
anchorU: 0.5,
|
||||
anchorV: 1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
await marker.startAnimation(TranslateMarkerAnimation(
|
||||
coordinate: getNextLatLng(),
|
||||
duration: Duration(milliseconds: 1000),
|
||||
repeatCount: 10000000,
|
||||
));
|
||||
await marker.setVisible(true);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加透明度动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider: _assetsIcon1,
|
||||
anchorU: 0.5,
|
||||
anchorV: 1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
await marker.startAnimation(AlphaMarkerAnimation(
|
||||
fromValue: 0,
|
||||
toValue: 1,
|
||||
duration: Duration(milliseconds: 1000),
|
||||
repeatCount: 0,
|
||||
));
|
||||
await marker.setVisible(true);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加旋转动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider: _assetsIcon1,
|
||||
anchorU: 0.5,
|
||||
anchorV: 1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
await marker.startAnimation(RotateMarkerAnimation(
|
||||
fromValue: 0,
|
||||
toValue: 100,
|
||||
duration: Duration(milliseconds: 1000),
|
||||
repeatCount: 0,
|
||||
));
|
||||
await marker.setVisible(true);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加混合动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider: _assetsIcon1,
|
||||
anchorU: 0.5,
|
||||
anchorV: 1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
await marker.startAnimation(MarkerAnimationSet(
|
||||
animationSet: [
|
||||
RotateMarkerAnimation(fromValue: 0, toValue: 100),
|
||||
AlphaMarkerAnimation(fromValue: 0, toValue: 1),
|
||||
ScaleMarkerAnimation(fromValue: 0.8, toValue: 1.2),
|
||||
],
|
||||
repeatCount: 0, duration: Duration(milliseconds: 1000),
|
||||
));
|
||||
await marker.setVisible(true);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加帧动画Marker')),
|
||||
onTap: () async {
|
||||
final marker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
title: '北京${random.nextDouble()}',
|
||||
snippet: '描述${random.nextDouble()}',
|
||||
iconsProvider: [
|
||||
for (int i = 0; i < 20; i++)
|
||||
AssetImage('images/animation$i.jpg')
|
||||
],
|
||||
animationFps: 3,
|
||||
object: '自定义数据${random.nextDouble()}',
|
||||
),
|
||||
);
|
||||
_markers.add(marker);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('移动Marker坐标')),
|
||||
onTap: () async {
|
||||
await _markers.first.setCoordinate(getNextLatLng());
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加一个不显示的marker')),
|
||||
onTap: () async {
|
||||
await _hiddenMarker.remove();
|
||||
_hiddenMarker = await _controller.addMarker(
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
title: '北京',
|
||||
snippet: '描述',
|
||||
iconProvider: _assetsIcon1,
|
||||
visible: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示隐藏的Marker',
|
||||
// selected: false,
|
||||
// onSelected: (visible) async {
|
||||
// await _hiddenMarker.setVisible(visible);
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('调用方法开启弹窗')),
|
||||
onTap: () async {
|
||||
if (_markers.isNotEmpty) {
|
||||
final marker = _markers[0];
|
||||
await marker.showInfoWindow();
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('调用方法关闭弹窗')),
|
||||
onTap: () async {
|
||||
if (_markers.isNotEmpty) {
|
||||
final marker = _markers[0];
|
||||
await marker.hideInfoWindow();
|
||||
}
|
||||
},
|
||||
),
|
||||
// ContinuousSetting(
|
||||
// head: '添加旋转角度的Marker',
|
||||
// onChanged: (value) async {
|
||||
// await _controller.clearMarkers(_markers);
|
||||
// final marker = await _controller.addMarker(
|
||||
// MarkerOption(
|
||||
// coordinate: LatLng(39.90960, 116.397228),
|
||||
// title: '北京',
|
||||
// snippet: '描述',
|
||||
// iconProvider: _assetsIcon1,
|
||||
// draggable: true,
|
||||
// rotateAngle: 360 * value,
|
||||
// anchorU: 0,
|
||||
// anchorV: 0,
|
||||
// ),
|
||||
// );
|
||||
// _markers.add(marker);
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Center(child: Text('批量添加Marker')),
|
||||
onTap: () {
|
||||
_controller.addMarkers(
|
||||
[
|
||||
for (int i = 0; i < 100; i++)
|
||||
MarkerOption(
|
||||
coordinate: getNextLatLng(),
|
||||
iconProvider:
|
||||
i % 2 == 0 ? _assetsIcon1 : _assetsIcon2,
|
||||
infoWindowEnabled: false,
|
||||
object: 'Marker_$i',
|
||||
),
|
||||
],
|
||||
).then(_markers.addAll);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除Marker')),
|
||||
onTap: () async {
|
||||
if (_markers.isNotEmpty) {
|
||||
await _markers[0].remove();
|
||||
_markers.removeAt(0);
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('清除所有Marker')),
|
||||
onTap: () async {
|
||||
await _controller.clearMarkers(_markers);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('清除所有覆盖物')),
|
||||
onTap: () async {
|
||||
await _controller.clear();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('Marker添加点击事件')),
|
||||
onTap: () {
|
||||
_controller.setMarkerClickedListener((marker) async {
|
||||
await marker.setIcon(
|
||||
_assetsIcon2,
|
||||
createLocalImageConfiguration(context),
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('Marker添加拖动事件')),
|
||||
onTap: () {
|
||||
_controller.setMarkerDragListener(
|
||||
onMarkerDragEnd: (marker) async {
|
||||
toast(
|
||||
'${await marker.title}, ${await marker.coordinate}',
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('将地图缩放至可以显示所有Marker')),
|
||||
onTap: () {
|
||||
Stream.fromIterable(_markers)
|
||||
.asyncMap((marker) => marker.coordinate)
|
||||
.toList()
|
||||
.then((boundary) {
|
||||
debugPrint('boundary: $boundary');
|
||||
_controller.zoomToSpan(
|
||||
boundary,
|
||||
padding: EdgeInsets.only(top: 100, bottom: 50),
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('监听Marker弹窗事件')),
|
||||
onTap: () async {
|
||||
await _controller
|
||||
.setInfoWindowClickListener((marker) async {
|
||||
toast(
|
||||
'${await marker.title}, ${await marker.coordinate}');
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('画热力图')),
|
||||
onTap: () async {
|
||||
await _controller.addHeatmapTileOverlay(
|
||||
HeatmapTileOption(
|
||||
coordinateList: getNextBatchLatLng(50),
|
||||
gradient: RadialGradient(
|
||||
colors: [Colors.blue, Colors.yellow, Colors.red],
|
||||
stops: <double>[0.08, 0.4, 1.0],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('(专业版)添加在线瓦片图')),
|
||||
onTap: () async {
|
||||
await _controller.addUrlTileOverlay(
|
||||
UrlTileOption(
|
||||
width: 256,
|
||||
height: 256,
|
||||
urlTemplate:
|
||||
// 'http://tile.opencyclemap.org/cycle/{scale}/{x}/{y}.png', // 由于没有api key, 这个链接无法显示瓦片
|
||||
'https://c2.hoopchina.com.cn/uploads/star/event/images/200709/bmiddle-34faa76c78ff3ba7a67282d64ff3c081135d4743.jpg?x-oss-process=image/resize,w_780,312',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加平滑移动点')),
|
||||
onTap: () async {
|
||||
_moveMarker = await _controller.addSmoothMoveMarker(
|
||||
SmoothMoveMarkerOption(
|
||||
path: [for (int i = 0; i < 10; i++) getNextLatLng()],
|
||||
iconProvider: _assetsIcon1,
|
||||
duration: Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
Future.delayed(
|
||||
Duration(seconds: 5),
|
||||
() => _moveMarker.stop(),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('进入二级地图页面')),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => DrawPointScreen()),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加海量点')),
|
||||
onTap: () async {
|
||||
_multiPointOverlay =
|
||||
await _controller.addMultiPointOverlay(
|
||||
MultiPointOption(
|
||||
pointList: [
|
||||
for (int i = 0; i < 10000; i++)
|
||||
PointOption(
|
||||
coordinate: getNextLatLng(),
|
||||
id: i.toString(),
|
||||
title: 'Point$i',
|
||||
snippet: 'Snippet$i',
|
||||
object: 'Object$i',
|
||||
)
|
||||
],
|
||||
iconProvider: _assetsIcon1,
|
||||
),
|
||||
);
|
||||
await _controller.setMultiPointClickedListener(
|
||||
(id, title, snippet, object) async {
|
||||
toast(
|
||||
'id: $id, title: $title, snippet: $snippet, object: $object',
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除海量点')),
|
||||
onTap: () async {
|
||||
await _multiPointOverlay.remove();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('修改title')),
|
||||
onTap: () {
|
||||
_markers.firstOrNull
|
||||
?..setTitle('修改title ${Random().nextInt(100)}')
|
||||
..showInfoWindow();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('修改snippet')),
|
||||
onTap: () {
|
||||
_markers.firstOrNull
|
||||
?..setSnippet('修改snippet ${Random().nextInt(100)}')
|
||||
..showInfoWindow();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
120
example/lib/map/draw_on_map/draw_polygon.screen.dart
Normal file
120
example/lib/map/draw_on_map/draw_polygon.screen.dart
Normal file
@ -0,0 +1,120 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DrawPolygonScreen extends StatefulWidget {
|
||||
DrawPolygonScreen();
|
||||
|
||||
factory DrawPolygonScreen.forDesignTime() => DrawPolygonScreen();
|
||||
|
||||
@override
|
||||
_DrawPolygonScreenState createState() => _DrawPolygonScreenState();
|
||||
}
|
||||
|
||||
class _DrawPolygonScreenState extends State<DrawPolygonScreen> with NextLatLng {
|
||||
late AmapController _controller;
|
||||
List<IPolygon> _polygonList = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('绘制多边形')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
zoomLevel: 10,
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Center(child: Text('添加多边形')),
|
||||
onTap: () async {
|
||||
final polygon = await _controller.addPolygon(PolygonOption(
|
||||
coordinateList: [
|
||||
LatLng(39.999391, 116.135972),
|
||||
LatLng(39.898323, 116.057694),
|
||||
LatLng(39.900430, 116.265061),
|
||||
LatLng(39.955192, 116.140092),
|
||||
],
|
||||
width: 10,
|
||||
strokeColor: Colors.green,
|
||||
));
|
||||
_polygonList.add(polygon);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加虚线折线')),
|
||||
onTap: () async {
|
||||
final polyline =
|
||||
await _controller.addPolyline(PolylineOption(
|
||||
coordinateList: [
|
||||
LatLng(39.999391, 116.135972),
|
||||
LatLng(39.898323, 116.057694),
|
||||
LatLng(39.900430, 116.265061),
|
||||
LatLng(39.955192, 116.140092),
|
||||
LatLng(39.999391, 116.135972),
|
||||
],
|
||||
width: 10,
|
||||
dashType: DashType.Square,
|
||||
));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加虚线填充多边形')),
|
||||
onTap: () async {
|
||||
await _controller.addPolyline(PolylineOption(
|
||||
coordinateList: [
|
||||
LatLng(39.999391, 116.135972),
|
||||
LatLng(39.898323, 116.057694),
|
||||
LatLng(39.900430, 116.265061),
|
||||
LatLng(39.955192, 116.140092),
|
||||
LatLng(39.999391, 116.135972),
|
||||
],
|
||||
width: 10,
|
||||
strokeColor: Colors.blue,
|
||||
dashType: DashType.Square,
|
||||
));
|
||||
final polygon = await _controller.addPolygon(PolygonOption(
|
||||
coordinateList: [
|
||||
LatLng(39.999391, 116.135972),
|
||||
LatLng(39.898323, 116.057694),
|
||||
LatLng(39.900430, 116.265061),
|
||||
LatLng(39.955192, 116.140092),
|
||||
],
|
||||
fillColor: Colors.blue.withOpacity(0.3),
|
||||
strokeColor: Colors.transparent,
|
||||
));
|
||||
_polygonList.add(polygon);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除多边形')),
|
||||
onTap: () async {
|
||||
if (_polygonList.isNotEmpty) {
|
||||
await _polygonList.first.remove();
|
||||
_polygonList.removeAt(0);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
273
example/lib/map/draw_on_map/draw_polyline.screen.dart
Normal file
273
example/lib/map/draw_on_map/draw_polyline.screen.dart
Normal file
@ -0,0 +1,273 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_map_fluttify_example/utils/next_latlng.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final _networkIcon = NetworkImage(
|
||||
'https://w3.hoopchina.com.cn/30/a7/6a/30a76aea75aef69e4ea0e7d3dee552c7001.jpg');
|
||||
final _assetsIcon1 = AssetImage('images/test_icon.png');
|
||||
final _assetsIcon2 = AssetImage('images/arrow.png');
|
||||
|
||||
class DrawPolylineScreen extends StatefulWidget {
|
||||
DrawPolylineScreen();
|
||||
|
||||
factory DrawPolylineScreen.forDesignTime() => DrawPolylineScreen();
|
||||
|
||||
@override
|
||||
_DrawPolylineScreenState createState() => _DrawPolylineScreenState();
|
||||
}
|
||||
|
||||
class _DrawPolylineScreenState extends State<DrawPolylineScreen>
|
||||
with NextLatLng {
|
||||
late AmapController _controller;
|
||||
late IPolyline _currentPolyline;
|
||||
late IPlaybackTrace _playbackTrace;
|
||||
List<LatLng> _pointList = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('绘制线')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
AmapView(
|
||||
tilt: 90,
|
||||
zoomLevel: 7,
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
Container(
|
||||
height: 100,
|
||||
color: Colors.black26,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Center(child: Text('添加线')),
|
||||
onTap: () async {
|
||||
_pointList = getNextBatchLatLng(3);
|
||||
|
||||
await _controller.addPolyline(PolylineOption(
|
||||
coordinateList: [
|
||||
LatLng(39.999391, 116.135972),
|
||||
LatLng(39.898323, 116.057694),
|
||||
LatLng(39.900430, 116.265061),
|
||||
LatLng(39.955192, 116.140092),
|
||||
],
|
||||
strokeColor: Colors.red,
|
||||
width: 10,
|
||||
));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('平滑处理')),
|
||||
onTap: () async {
|
||||
if (_currentPolyline == null) {
|
||||
toast('请先添加对比折线');
|
||||
return;
|
||||
}
|
||||
final smooth =
|
||||
await AmapService.instance.pathSmooth(_pointList);
|
||||
await _controller.addPolyline(PolylineOption(
|
||||
coordinateList: smooth,
|
||||
width: 10,
|
||||
strokeColor: Colors.green,
|
||||
));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('将地图缩放至可以显示所有Marker')),
|
||||
onTap: () async {
|
||||
await _controller.zoomToSpan(
|
||||
_pointList,
|
||||
padding: EdgeInsets.only(top: 100),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加线(自定义纹理)')),
|
||||
onTap: () async {
|
||||
await _currentPolyline?.remove();
|
||||
_currentPolyline =
|
||||
await _controller.addPolyline(PolylineOption(
|
||||
coordinateList: [
|
||||
getNextLatLng(),
|
||||
getNextLatLng(),
|
||||
getNextLatLng(),
|
||||
getNextLatLng(),
|
||||
],
|
||||
width: 10,
|
||||
textureProvider: _assetsIcon2,
|
||||
));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除折线')),
|
||||
onTap: () => _currentPolyline?.remove(),
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('绘制北京行政区域边界')),
|
||||
onTap: () => _controller.addDistrictOutline('北京'),
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('添加回放轨迹')),
|
||||
onTap: () async {
|
||||
final result = await AmapSearch.instance.searchDriveRoute(
|
||||
from: LatLng(39.958245, 116.330929),
|
||||
to: LatLng(39.915599, 116.42912),
|
||||
);
|
||||
final pathList = await result.drivePathList;
|
||||
final stepList = [
|
||||
for (final path in pathList) ...await path.driveStepList
|
||||
];
|
||||
final coordinateList = [
|
||||
for (final step in stepList) ...await step.polyline
|
||||
];
|
||||
_playbackTrace = await _controller.addPlaybackTrace(
|
||||
coordinateList,
|
||||
iconProvider: _assetsIcon1,
|
||||
duration: Duration(seconds: 10),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('删除回放轨迹')),
|
||||
onTap: () async {
|
||||
_playbackTrace?.remove();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Center(child: Text('给折线添加点')),
|
||||
onTap: () async {
|
||||
_pointList = [..._pointList, getNextLatLng()];
|
||||
await _currentPolyline?.setCoordinateList(_pointList);
|
||||
},
|
||||
),
|
||||
// DiscreteSetting(
|
||||
// head: '选择始末端样式',
|
||||
// options: [
|
||||
// '普通头',
|
||||
// '扩展头',
|
||||
// '箭头',
|
||||
// '圆形头',
|
||||
// ],
|
||||
// onSelected: (value) async {
|
||||
// LineCapType type;
|
||||
// switch (value) {
|
||||
// case '普通头':
|
||||
// type = LineCapType.Butt;
|
||||
// break;
|
||||
// case '扩展头':
|
||||
// type = LineCapType.Square;
|
||||
// break;
|
||||
// case '箭头':
|
||||
// type = LineCapType.Arrow;
|
||||
// break;
|
||||
// case '圆形头':
|
||||
// type = LineCapType.Round;
|
||||
// break;
|
||||
// }
|
||||
// await _currentPolyline?.remove();
|
||||
// _currentPolyline =
|
||||
// await _controller.addPolyline(PolylineOption(
|
||||
// coordinateList: [
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// ],
|
||||
// width: 10,
|
||||
// strokeColor: Colors.green,
|
||||
// lineCapType: type,
|
||||
// ));
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '选择连接点样式',
|
||||
// options: [
|
||||
// '斜面连接点',
|
||||
// '斜接连接点',
|
||||
// '圆角连接点',
|
||||
// ],
|
||||
// onSelected: (value) async {
|
||||
// LineJoinType type;
|
||||
// switch (value) {
|
||||
// case '斜面连接点':
|
||||
// type = LineJoinType.Bevel;
|
||||
// break;
|
||||
// case '斜接连接点':
|
||||
// type = LineJoinType.Miter;
|
||||
// break;
|
||||
// case '圆角连接点':
|
||||
// type = LineJoinType.Round;
|
||||
// break;
|
||||
// }
|
||||
// await _currentPolyline?.remove();
|
||||
// _currentPolyline =
|
||||
// await _controller.addPolyline(PolylineOption(
|
||||
// coordinateList: [
|
||||
// LatLng(39.999391, 116.135972),
|
||||
// LatLng(39.898323, 116.057694),
|
||||
// LatLng(39.900430, 116.265061),
|
||||
// LatLng(39.955192, 116.140092),
|
||||
// ],
|
||||
// width: 10,
|
||||
// strokeColor: Colors.green,
|
||||
// lineJoinType: type,
|
||||
// ));
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '选择始折线样式',
|
||||
// options: [
|
||||
// '普通折线',
|
||||
// '方块虚线',
|
||||
// '圆形虚线',
|
||||
// ],
|
||||
// onSelected: (value) async {
|
||||
// DashType type;
|
||||
// switch (value) {
|
||||
// case '普通折线':
|
||||
// type = null;
|
||||
// break;
|
||||
// case '方块虚线':
|
||||
// type = DashType.Square;
|
||||
// break;
|
||||
// case '圆形虚线':
|
||||
// type = DashType.Circle;
|
||||
// break;
|
||||
// }
|
||||
// await _currentPolyline?.remove();
|
||||
// _currentPolyline =
|
||||
// await _controller.addPolyline(PolylineOption(
|
||||
// coordinateList: [
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// getNextLatLng(),
|
||||
// ],
|
||||
// width: 10,
|
||||
// strokeColor: Colors.green,
|
||||
// dashType: type,
|
||||
// ));
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
114
example/lib/map/interact_with_map/code_interaction.screen.dart
Normal file
114
example/lib/map/interact_with_map/code_interaction.screen.dart
Normal file
@ -0,0 +1,114 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
//const beijing = LatLng(39.90960, 116.397228);
|
||||
//const shanghai = LatLng(31.22, 121.48);
|
||||
//const guangzhou = LatLng(23.16, 113.23);
|
||||
|
||||
class CodeInteractionScreen extends StatefulWidget {
|
||||
CodeInteractionScreen();
|
||||
|
||||
factory CodeInteractionScreen.forDesignTime() => CodeInteractionScreen();
|
||||
|
||||
@override
|
||||
_CodeInteractionScreenState createState() => _CodeInteractionScreenState();
|
||||
}
|
||||
|
||||
class _CodeInteractionScreenState extends State<CodeInteractionScreen> {
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('调用方法交互')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
// ContinuousSetting(
|
||||
// head: '缩放大小',
|
||||
// min: 0,
|
||||
// max: 20,
|
||||
// onChanged: (value) {
|
||||
// _controller.setZoomLevel(value);
|
||||
// },
|
||||
// ),
|
||||
// ContinuousSetting(
|
||||
// head: '(专业版)设置地图朝向',
|
||||
// min: 0,
|
||||
// max: 360,
|
||||
// onChanged: (value) {
|
||||
// debugPrint('bearing value: $value');
|
||||
// _controller.setBearing(105);
|
||||
// },
|
||||
// ),
|
||||
// ContinuousSetting(
|
||||
// head: '(专业版)设置地图倾斜度',
|
||||
// min: 0,
|
||||
// max: 90,
|
||||
// onChanged: (value) {
|
||||
// _controller.setTilt(value);
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '放大/缩小一个等级',
|
||||
// options: ['放大', '缩小'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '放大':
|
||||
// _controller.zoomIn();
|
||||
// break;
|
||||
// case '缩小':
|
||||
// _controller.zoomOut();
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// DiscreteSetting(
|
||||
// head: '设置地图中心点',
|
||||
// options: ['广州', '北京', '上海'],
|
||||
// onSelected: (value) {
|
||||
// switch (value) {
|
||||
// case '广州':
|
||||
// _controller.setCenterCoordinate(
|
||||
// LatLng(23.16, 113.23),
|
||||
// animated: false,
|
||||
// );
|
||||
// break;
|
||||
// case '北京':
|
||||
// _controller.setCenterCoordinate(
|
||||
// LatLng(39.90960, 116.397228),
|
||||
// animated: true,
|
||||
// );
|
||||
// break;
|
||||
// case '上海':
|
||||
// _controller.setCenterCoordinate(LatLng(31.22, 121.48));
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ControlInteractionScreen extends StatefulWidget {
|
||||
ControlInteractionScreen();
|
||||
|
||||
factory ControlInteractionScreen.forDesignTime() =>
|
||||
ControlInteractionScreen();
|
||||
|
||||
@override
|
||||
_ControlInteractionScreenState createState() =>
|
||||
_ControlInteractionScreenState();
|
||||
}
|
||||
|
||||
class _ControlInteractionScreenState extends State<ControlInteractionScreen> {
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('控件交互')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
// BooleanSetting(
|
||||
// head: '是否显示缩放按钮',
|
||||
// onSelected: (value) {
|
||||
// _controller.showZoomControl(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示指南针',
|
||||
// onSelected: (value) {
|
||||
// _controller.showCompass(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示定位按钮',
|
||||
// onSelected: (value) {
|
||||
// _controller.showLocateControl(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否显示比例尺',
|
||||
// onSelected: (value) {
|
||||
// _controller.showScaleControl(value);
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GestureInteractionScreen extends StatefulWidget {
|
||||
GestureInteractionScreen();
|
||||
|
||||
factory GestureInteractionScreen.forDesignTime() =>
|
||||
GestureInteractionScreen();
|
||||
|
||||
@override
|
||||
_GestureInteractionScreenState createState() =>
|
||||
_GestureInteractionScreenState();
|
||||
}
|
||||
|
||||
class _GestureInteractionScreenState extends State<GestureInteractionScreen> {
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('手势交互')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: DecoratedColumn(
|
||||
scrollable: true,
|
||||
divider: Divider(height: 1),
|
||||
children: <Widget>[
|
||||
// BooleanSetting(
|
||||
// head: '是否使能缩放手势',
|
||||
// onSelected: (value) {
|
||||
// _controller.setZoomGesturesEnabled(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否使能滑动手势',
|
||||
// onSelected: (value) {
|
||||
// _controller.setScrollGesturesEnabled(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否使能旋转手势',
|
||||
// onSelected: (value) {
|
||||
// _controller.setRotateGesturesEnabled(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否使能倾斜手势',
|
||||
// onSelected: (value) {
|
||||
// _controller.setTiltGesturesEnabled(value);
|
||||
// },
|
||||
// ),
|
||||
// BooleanSetting(
|
||||
// head: '是否使能所有手势',
|
||||
// onSelected: (value) {
|
||||
// _controller.setAllGesturesEnabled(value);
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
52
example/lib/map/interact_with_map/screen_shot_screen.dart
Normal file
52
example/lib/map/interact_with_map/screen_shot_screen.dart
Normal file
@ -0,0 +1,52 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ScreenShotScreen extends StatefulWidget {
|
||||
@override
|
||||
_ScreenShotScreenState createState() => _ScreenShotScreenState();
|
||||
}
|
||||
|
||||
class _ScreenShotScreenState extends State<ScreenShotScreen> {
|
||||
late Uint8List _data;
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('截图')),
|
||||
body: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AmapView(
|
||||
maskDelay: Duration(milliseconds: 500),
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: DecoratedColumn(
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final data = await _controller.screenShot();
|
||||
setState(() {
|
||||
_data = data;
|
||||
});
|
||||
},
|
||||
child: Text('截图'),
|
||||
),
|
||||
if (_data != null) Image.memory(_data)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
109
example/lib/map/location/geo_fence.screen.dart
Normal file
109
example/lib/map/location/geo_fence.screen.dart
Normal file
@ -0,0 +1,109 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:amap_location_fluttify/amap_location_fluttify.dart';
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:amap_search_fluttify/amap_search_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final random = Random();
|
||||
|
||||
class GeoFenceScreen extends StatefulWidget {
|
||||
@override
|
||||
_GeoFenceScreenState createState() => _GeoFenceScreenState();
|
||||
}
|
||||
|
||||
class _GeoFenceScreenState extends State<GeoFenceScreen> {
|
||||
late AmapController _controller;
|
||||
late List<LatLng> _fenceCoordinateList;
|
||||
late IPolygon _fencePolygon;
|
||||
late String _fenceState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fenceCoordinateList = [];
|
||||
_fenceState = '点击地图创建电子围栏';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
AmapView(
|
||||
zoomLevel: 10,
|
||||
showZoomControl: false,
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
await _controller.setMapClickedListener(_handleMapClick);
|
||||
await _controller.showMyLocation(MyLocationOption(
|
||||
strokeColor: Colors.transparent,
|
||||
fillColor: Colors.transparent,
|
||||
));
|
||||
await Future.delayed(Duration(milliseconds: 1200));
|
||||
final coordinate = await _controller.getLocation();
|
||||
await _controller.setCameraPosition(
|
||||
coordinate: coordinate!,
|
||||
zoom: 17,
|
||||
tilt: 90,
|
||||
);
|
||||
// 搜索poi
|
||||
final poiList =
|
||||
await AmapSearch.instance.searchAround(coordinate);
|
||||
await _controller.addMarkers([
|
||||
for (final poi in poiList)
|
||||
MarkerOption(
|
||||
coordinate: poi.latLng!,
|
||||
iconProvider: AssetImage('images/test_icon.png'),
|
||||
title: poi.title!,
|
||||
snippet: poi.address!,
|
||||
object: '自定义数据: ${poi.poiId}',
|
||||
)
|
||||
]);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
left: kSpace16,
|
||||
right: kSpace16,
|
||||
bottom: kSpace16,
|
||||
child: IgnorePointer(
|
||||
child: Text(_fenceState, style: context.textTheme.headlineLarge),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: Icon(Icons.clear),
|
||||
tooltip: '清除电子围栏',
|
||||
onPressed: () => _handleClearGeoFence(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleMapClick(LatLng latLng) async {
|
||||
_fenceCoordinateList.add(latLng);
|
||||
final content =
|
||||
'${_fenceCoordinateList.length < 3 ? '已点击${_fenceCoordinateList.length}个点, 请继续点击至三个点以上\n' : ''}点击地图坐标: ${latLng.latitude}, ${latLng.longitude}';
|
||||
toast(content);
|
||||
if (_fenceCoordinateList.isNotEmpty) {
|
||||
_fencePolygon.remove();
|
||||
_fencePolygon = await _controller.addPolygon(PolygonOption(
|
||||
coordinateList: _fenceCoordinateList,
|
||||
));
|
||||
AmapLocation.instance
|
||||
.addPolygonGeoFence(pointList: _fenceCoordinateList)
|
||||
.listen((event) {
|
||||
setState(() => _fenceState = '电子围栏事件: ${event.toString()}');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _handleClearGeoFence(BuildContext context) {
|
||||
_fenceCoordinateList.clear();
|
||||
_fencePolygon.remove();
|
||||
setState(() {
|
||||
_fenceState = '点击地图创建电子围栏';
|
||||
});
|
||||
}
|
||||
}
|
176
example/lib/map/map.screen.dart
Normal file
176
example/lib/map/map.screen.dart
Normal file
@ -0,0 +1,176 @@
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'create_map/create_map.screen.dart';
|
||||
import 'create_map/multi_map.screen.dart';
|
||||
import 'draw_on_map/draw_circle.screen.dart';
|
||||
import 'draw_on_map/draw_ground_overlay.screen.dart';
|
||||
import 'draw_on_map/draw_point.screen.dart';
|
||||
import 'draw_on_map/draw_polygon.screen.dart';
|
||||
import 'draw_on_map/draw_polyline.screen.dart';
|
||||
import 'interact_with_map/code_interaction.screen.dart';
|
||||
import 'interact_with_map/control_interaction.screen.dart';
|
||||
import 'interact_with_map/gesture_interaction.screen.dart';
|
||||
import 'interact_with_map/screen_shot_screen.dart';
|
||||
import 'location/geo_fence.screen.dart';
|
||||
import 'tools/calcute_distance_screen.dart';
|
||||
import 'tools/coordinate_transformation_screen.dart';
|
||||
import 'tools/launch_amap_screen.dart';
|
||||
import 'tools/location_picker/location_picker.screen.dart';
|
||||
import 'tools/offline_manager_screen.dart';
|
||||
import 'tools/processed_trace.screen.dart';
|
||||
import 'tools/static_image.screen.dart';
|
||||
|
||||
class MapDemo extends StatefulWidget {
|
||||
@override
|
||||
_MapDemoState createState() => _MapDemoState();
|
||||
}
|
||||
|
||||
class _MapDemoState extends State<MapDemo> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 缓存地图需要的图片
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
precacheImage(AssetImage('images/test_icon.png'), context);
|
||||
precacheImage(AssetImage('images/arrow.png'), context);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
ElevatedButton(onPressed: () {
|
||||
// 跳转路由
|
||||
// CreateMapScreen();
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) => CreateMapScreen()));
|
||||
}, child: Text("显示地图")),
|
||||
// FunctionGroup(
|
||||
// headLabel: '创建地图',
|
||||
// children: <Widget>[
|
||||
// FunctionItem(
|
||||
// label: '显示地图',
|
||||
// sublabel: 'CreateMapScreen',
|
||||
// target: CreateMapScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '显示多地图',
|
||||
// sublabel: 'MultiMapScreen',
|
||||
// target: MultiMapScreen(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SPACE_16,
|
||||
// FunctionGroup(
|
||||
// headLabel: '与地图交互',
|
||||
// children: <Widget>[
|
||||
// FunctionItem(
|
||||
// label: '控件交互',
|
||||
// sublabel: 'ControlInteractionScreen',
|
||||
// target: ControlInteractionScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '手势交互',
|
||||
// sublabel: 'GestureInteractionScreen',
|
||||
// target: GestureInteractionScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '调用方法交互',
|
||||
// sublabel: 'CodeInteractionScreen',
|
||||
// target: CodeInteractionScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '截图',
|
||||
// sublabel: 'ScreenShotScreen',
|
||||
// target: ScreenShotScreen(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SPACE_16,
|
||||
// FunctionGroup(
|
||||
// headLabel: '在地图上绘制',
|
||||
// children: <Widget>[
|
||||
// FunctionItem(
|
||||
// label: '绘制点标记',
|
||||
// sublabel: 'DrawPointScreen',
|
||||
// target: DrawPointScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '绘制线',
|
||||
// sublabel: 'DrawPolylineScreen',
|
||||
// target: DrawPolylineScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '绘制圆',
|
||||
// sublabel: 'DrawCircleScreen',
|
||||
// target: DrawCircleScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '绘制多边形',
|
||||
// sublabel: 'DrawPolygonScreen',
|
||||
// target: DrawPolygonScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: '绘制图片覆盖物',
|
||||
// sublabel: 'DrawGroundOverlayScreen',
|
||||
// target: DrawGroundOverlayScreen(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SPACE_16,
|
||||
// FunctionGroup(
|
||||
// headLabel: "工具",
|
||||
// children: <Widget>[
|
||||
// FunctionItem(
|
||||
// label: "坐标转换",
|
||||
// sublabel: "CoordinateTransformationScreen",
|
||||
// target: CoordinateTransformationScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "两点间距离计算",
|
||||
// sublabel: "CalculateDistanceScreen",
|
||||
// target: CalculateDistanceScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "调用高德地图",
|
||||
// sublabel: "LaunchAmapScreen",
|
||||
// target: LaunchAmapScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "轨迹纠偏",
|
||||
// sublabel: "ProcessedTraceScreen",
|
||||
// target: ProcessedTraceScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "离线地图",
|
||||
// sublabel: "OfflineManagerScreen",
|
||||
// target: OfflineManagerScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "获取静态图",
|
||||
// sublabel: "StaticImageScreen",
|
||||
// target: StaticImageScreen(),
|
||||
// ),
|
||||
// FunctionItem(
|
||||
// label: "选择地址",
|
||||
// sublabel: "LocationPickerScreen",
|
||||
// target: LocationPickerScreen(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SPACE_16,
|
||||
// FunctionGroup(
|
||||
// headLabel: "定位",
|
||||
// children: <Widget>[
|
||||
// FunctionItem(
|
||||
// label: "(专业版)电子围栏",
|
||||
// sublabel: "GeoFenceScreen",
|
||||
// target: GeoFenceScreen(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
89
example/lib/map/tools/calcute_distance_screen.dart
Normal file
89
example/lib/map/tools/calcute_distance_screen.dart
Normal file
@ -0,0 +1,89 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CalculateDistanceScreen extends StatefulWidget {
|
||||
@override
|
||||
CalculateDistanceStateScreen createState() => CalculateDistanceStateScreen();
|
||||
}
|
||||
|
||||
class CalculateDistanceStateScreen extends State<CalculateDistanceScreen> {
|
||||
final _point1LatController = TextEditingController(text: '29');
|
||||
final _point1LngController = TextEditingController(text: '119');
|
||||
final _point2LatController = TextEditingController(text: '30');
|
||||
final _point2LngController = TextEditingController(text: '119');
|
||||
|
||||
double _result = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('距离计算'),
|
||||
),
|
||||
body: DecoratedColumn(
|
||||
padding: EdgeInsets.all(kSpace16),
|
||||
children: <Widget>[
|
||||
DecoratedRow(
|
||||
itemSpacing: kSpace8,
|
||||
children: <Widget>[
|
||||
Text('点1:'),
|
||||
Flexible(
|
||||
child: TextFormField(
|
||||
controller: _point1LatController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(hintText: '输入点1纬度'),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextFormField(
|
||||
controller: _point1LngController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(hintText: '输入点1经度'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
DecoratedRow(
|
||||
itemSpacing: kSpace8,
|
||||
children: <Widget>[
|
||||
Text('点2:'),
|
||||
Flexible(
|
||||
child: TextFormField(
|
||||
controller: _point2LatController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(hintText: '输入点2纬度'),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextFormField(
|
||||
controller: _point2LngController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(hintText: '输入点2经度'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance.calculateDistance(
|
||||
LatLng(
|
||||
double.parse(_point1LatController.text),
|
||||
double.parse(_point1LngController.text),
|
||||
),
|
||||
LatLng(
|
||||
double.parse(_point2LatController.text),
|
||||
double.parse(_point2LngController.text),
|
||||
),
|
||||
);
|
||||
|
||||
setState(() => _result = result);
|
||||
},
|
||||
child: Text('计算'),
|
||||
),
|
||||
Text(_result.toString() + '米'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
132
example/lib/map/tools/coordinate_transformation_screen.dart
Normal file
132
example/lib/map/tools/coordinate_transformation_screen.dart
Normal file
@ -0,0 +1,132 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CoordinateTransformationScreen extends StatefulWidget {
|
||||
@override
|
||||
_CoordinateTransformationStateScreen createState() =>
|
||||
_CoordinateTransformationStateScreen();
|
||||
}
|
||||
|
||||
class _CoordinateTransformationStateScreen
|
||||
extends State<CoordinateTransformationScreen> {
|
||||
final _latController = TextEditingController(text: "39.914266");
|
||||
final _lngController = TextEditingController(text: "116.403988");
|
||||
|
||||
final _coord = LatLng(39.914266, 116.403988);
|
||||
LatLng _target = LatLng(39.914266, 116.403988);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('坐标转换')),
|
||||
body: DecoratedColumn(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
children: <Widget>[
|
||||
SPACE_8,
|
||||
TextFormField(
|
||||
readOnly: true,
|
||||
controller: _latController,
|
||||
decoration: InputDecoration(
|
||||
labelText: "纬度 latitude",
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
enabled: false,
|
||||
),
|
||||
SPACE_8,
|
||||
TextFormField(
|
||||
readOnly: true,
|
||||
controller: _lngController,
|
||||
decoration: InputDecoration(
|
||||
labelText: "经度 longitude",
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
enabled: false,
|
||||
),
|
||||
SPACE_8,
|
||||
Text('转换结果: ${_target.latitude}, ${_target.longitude}'),
|
||||
SPACE_8,
|
||||
GridView.count(
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 3,
|
||||
mainAxisSpacing: kSpace8,
|
||||
crossAxisSpacing: kSpace8,
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.GPS);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('GPS'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.Google);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('Google'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.MapBar);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('MapBar'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.Baidu);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('Baidu'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.MapABC);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('MapABC'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.SosoMap);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('SosoMap'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final result = await AmapService.instance
|
||||
.convertCoordinate(_coord, CoordType.Aliyun);
|
||||
setState(() {
|
||||
_target = result;
|
||||
});
|
||||
},
|
||||
child: Text('Aliyun'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
38
example/lib/map/tools/launch_amap_screen.dart
Normal file
38
example/lib/map/tools/launch_amap_screen.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LaunchAmapScreen extends StatefulWidget {
|
||||
@override
|
||||
_LaunchAmapScreenState createState() => _LaunchAmapScreenState();
|
||||
}
|
||||
|
||||
class _LaunchAmapScreenState extends State<LaunchAmapScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('调用高德地图')),
|
||||
body: Center(
|
||||
child: DecoratedColumn(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapService.instance
|
||||
.navigateDrive(LatLng(36.547901, 104.258354));
|
||||
},
|
||||
child: Text('高德地图驾车导航'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapService.instance
|
||||
.navigateRide(LatLng(36.547901, 104.258354));
|
||||
},
|
||||
child: Text('高德地图骑行导航'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'location_picker.widget.dart';
|
||||
|
||||
class LocationPickerScreen extends StatefulWidget {
|
||||
@override
|
||||
_LocationPickerScreenState createState() => _LocationPickerScreenState();
|
||||
}
|
||||
|
||||
class _LocationPickerScreenState extends State<LocationPickerScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
// body: LocationPicker(
|
||||
// requestPermission: () {
|
||||
// return Permission.location.request().then((it) => it.isGranted);
|
||||
// },
|
||||
// poiItemBuilder: (poi, selected) {
|
||||
// return ListTile(
|
||||
// title: Text(poi.title!),
|
||||
// subtitle: Text(poi.address!),
|
||||
// trailing: selected ? Icon(Icons.check) : SizedBox.shrink(),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
||||
import 'package:flutter_easyrefresh/material_footer.dart';
|
||||
import 'package:sliding_up_panel/sliding_up_panel.dart';
|
||||
|
||||
import 'models.dart';
|
||||
|
||||
const _iconSize = 50.0;
|
||||
const _package = 'amap_all_fluttify';
|
||||
const _indicator = 'images/indicator.png';
|
||||
double _fabHeight = 16.0;
|
||||
|
||||
typedef RequestPermission = Future<bool> Function();
|
||||
typedef PoiItemBuilder = Widget Function(Poi poi, bool selected);
|
||||
|
||||
class LocationPicker extends StatefulWidget {
|
||||
const LocationPicker({
|
||||
required Key key,
|
||||
required this.requestPermission,
|
||||
required this.poiItemBuilder,
|
||||
this.zoomLevel = 16.0,
|
||||
this.zoomGesturesEnabled = false,
|
||||
this.showZoomControl = false,
|
||||
required this.centerIndicator,
|
||||
this.enableLoadMore = true,
|
||||
required this.onItemSelected,
|
||||
}) : assert(zoomLevel >= 3 && zoomLevel <= 19),
|
||||
super(key: key);
|
||||
|
||||
/// 请求权限回调
|
||||
final RequestPermission requestPermission;
|
||||
|
||||
/// Poi列表项Builder
|
||||
final PoiItemBuilder poiItemBuilder;
|
||||
|
||||
/// 显示的缩放登记
|
||||
final double zoomLevel;
|
||||
|
||||
/// 缩放手势使能 默认false
|
||||
final bool zoomGesturesEnabled;
|
||||
|
||||
/// 是否显示缩放控件 默认false
|
||||
final bool showZoomControl;
|
||||
|
||||
/// 地图中心指示器
|
||||
final Widget centerIndicator;
|
||||
|
||||
/// 是否开启加载更多
|
||||
final bool enableLoadMore;
|
||||
|
||||
/// 选中回调
|
||||
final ValueChanged<PoiInfo> onItemSelected;
|
||||
|
||||
@override
|
||||
_LocationPickerState createState() => _LocationPickerState();
|
||||
}
|
||||
|
||||
class _LocationPickerState extends State<LocationPicker>
|
||||
with SingleTickerProviderStateMixin, _BLoCMixin, _AnimationMixin {
|
||||
// 地图控制器
|
||||
late AmapController _controller;
|
||||
final PanelController _panelController = PanelController();
|
||||
|
||||
// 是否用户手势移动地图
|
||||
bool _moveByUser = true;
|
||||
|
||||
// 当前请求到的poi列表
|
||||
List<PoiInfo> _poiInfoList = [];
|
||||
|
||||
// 当前地图中心点
|
||||
late LatLng _currentCenterCoordinate;
|
||||
|
||||
// 页数
|
||||
int _page = 1;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final minPanelHeight = MediaQuery.of(context).size.height * 0.4;
|
||||
final maxPanelHeight = MediaQuery.of(context).size.height * 0.7;
|
||||
return SlidingUpPanel(
|
||||
controller: _panelController,
|
||||
parallaxEnabled: true,
|
||||
parallaxOffset: 0.5,
|
||||
minHeight: minPanelHeight,
|
||||
maxHeight: maxPanelHeight,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
onPanelSlide: (double pos) => setState(() {
|
||||
_fabHeight = pos * (maxPanelHeight - minPanelHeight) * .5 + 16;
|
||||
}),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
AmapView(
|
||||
zoomLevel: widget.zoomLevel,
|
||||
zoomGesturesEnabled: widget.zoomGesturesEnabled,
|
||||
showZoomControl: widget.showZoomControl,
|
||||
onMapMoveEnd: (move) async {
|
||||
if (_moveByUser) {
|
||||
// 地图移动结束, 显示跳动动画
|
||||
_jumpController
|
||||
.forward()
|
||||
.then((it) => _jumpController.reverse());
|
||||
_search(move.coordinate!);
|
||||
}
|
||||
_moveByUser = true;
|
||||
// 保存当前地图中心点数据
|
||||
_currentCenterCoordinate = move.coordinate!;
|
||||
},
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
if (await widget.requestPermission()) {
|
||||
await _showMyLocation();
|
||||
var latLng = await _controller.getLocation();
|
||||
_search(latLng!);
|
||||
} else {
|
||||
debugPrint('权限请求被拒绝!');
|
||||
}
|
||||
},
|
||||
),
|
||||
// 中心指示器
|
||||
Center(
|
||||
child: AnimatedBuilder(
|
||||
animation: _tween,
|
||||
builder: (context, child) {
|
||||
return Transform.translate(
|
||||
offset: Offset(
|
||||
_tween.value.dx,
|
||||
_tween.value.dy - _iconSize / 2,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: widget.centerIndicator ??
|
||||
Image.asset(
|
||||
_indicator,
|
||||
height: _iconSize,
|
||||
package: _package,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 定位按钮
|
||||
Positioned(
|
||||
right: 16.0,
|
||||
bottom: _fabHeight,
|
||||
child: FloatingActionButton(
|
||||
child: StreamBuilder<bool>(
|
||||
stream: _onMyLocation.stream,
|
||||
initialData: true,
|
||||
builder: (context, snapshot) {
|
||||
return Icon(
|
||||
Icons.gps_fixed,
|
||||
color: snapshot.data!
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.black54,
|
||||
);
|
||||
},
|
||||
),
|
||||
onPressed: _showMyLocation,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 用来抵消panel的最小高度
|
||||
SizedBox(height: minPanelHeight),
|
||||
],
|
||||
),
|
||||
panelBuilder: (scrollController) {
|
||||
return StreamBuilder<List<PoiInfo>>(
|
||||
stream: _poiStream.stream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final data = snapshot.data;
|
||||
return EasyRefresh(
|
||||
footer: MaterialFooter(),
|
||||
onLoad: widget.enableLoadMore ? _handleLoadMore : null,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: scrollController,
|
||||
shrinkWrap: true,
|
||||
itemCount: data!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final poi = data[index].poi;
|
||||
final selected = data[index].selected;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
// 遍历数据列表, 设置当前被选中的数据项
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i].selected = i == index;
|
||||
}
|
||||
// 如果索引是0, 说明是当前位置, 更新这个数据
|
||||
_onMyLocation.add(index == 0);
|
||||
// 刷新数据
|
||||
_poiStream.add(data);
|
||||
// 设置地图中心点
|
||||
_setCenterCoordinate(poi.latLng!);
|
||||
// 回调
|
||||
widget.onItemSelected(data[index]);
|
||||
},
|
||||
child: widget.poiItemBuilder(poi, selected),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _search(LatLng location) async {
|
||||
final poiList = await AmapSearch.instance.searchAround(location);
|
||||
_poiInfoList = poiList.map((poi) => PoiInfo(poi)).toList();
|
||||
// 默认勾选第一项
|
||||
if (_poiInfoList.isNotEmpty) _poiInfoList[0].selected = true;
|
||||
_poiStream.add(_poiInfoList);
|
||||
|
||||
// 重置页数
|
||||
_page = 1;
|
||||
}
|
||||
|
||||
Future<void> _showMyLocation() async {
|
||||
_onMyLocation.add(true);
|
||||
await _controller.showMyLocation(MyLocationOption(
|
||||
strokeColor: Colors.transparent,
|
||||
fillColor: Colors.transparent,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _setCenterCoordinate(LatLng coordinate) async {
|
||||
await _controller.setCenterCoordinate(coordinate);
|
||||
_moveByUser = false;
|
||||
}
|
||||
|
||||
Future<void> _handleLoadMore() async {
|
||||
final poiList = await AmapSearch.instance.searchAround(
|
||||
_currentCenterCoordinate,
|
||||
page: ++_page,
|
||||
);
|
||||
_poiInfoList.addAll(poiList.map((poi) => PoiInfo(poi)).toList());
|
||||
_poiStream.add(_poiInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
mixin _BLoCMixin on State<LocationPicker> {
|
||||
// poi流
|
||||
final _poiStream = StreamController<List<PoiInfo>>();
|
||||
|
||||
// 是否在我的位置
|
||||
final _onMyLocation = StreamController<bool>();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_poiStream.close();
|
||||
_onMyLocation.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
mixin _AnimationMixin on SingleTickerProviderStateMixin<LocationPicker> {
|
||||
// 动画相关
|
||||
late AnimationController _jumpController;
|
||||
late Animation<Offset> _tween;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_jumpController =
|
||||
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
|
||||
_tween = Tween(begin: Offset(0, 0), end: Offset(0, -15)).animate(
|
||||
CurvedAnimation(parent: _jumpController, curve: Curves.easeInOut));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_jumpController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
13
example/lib/map/tools/location_picker/models.dart
Normal file
13
example/lib/map/tools/location_picker/models.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:amap_search_fluttify/amap_search_fluttify.dart';
|
||||
|
||||
class PoiInfo {
|
||||
PoiInfo(this.poi);
|
||||
|
||||
final Poi poi;
|
||||
bool selected = false;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PoiInfo{poi: $poi, selected: $selected}';
|
||||
}
|
||||
}
|
19
example/lib/map/tools/offline_manager_screen.dart
Normal file
19
example/lib/map/tools/offline_manager_screen.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OfflineManagerScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('打开离线地图管理')),
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapService.instance.openOfflineMapManager();
|
||||
},
|
||||
child: Text('离线地图管理'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
61
example/lib/map/tools/processed_trace.screen.dart
Normal file
61
example/lib/map/tools/processed_trace.screen.dart
Normal file
@ -0,0 +1,61 @@
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ProcessedTraceScreen extends StatefulWidget {
|
||||
@override
|
||||
ProcessedTraceStateScreen createState() => ProcessedTraceStateScreen();
|
||||
}
|
||||
|
||||
class ProcessedTraceStateScreen extends State<ProcessedTraceScreen> {
|
||||
List<LatLng> _result = [];
|
||||
|
||||
late AmapController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('轨迹纠偏'),
|
||||
),
|
||||
body: DecoratedColumn(
|
||||
padding: EdgeInsets.all(kSpace16),
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: AmapView(
|
||||
onMapCreated: (controller) async {
|
||||
_controller = controller;
|
||||
await controller.setMapClickedListener((latLng) async {
|
||||
_result.add(latLng);
|
||||
await controller.addMarker(MarkerOption(coordinate: latLng));
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
await AmapService.instance.queryProcessedTrace(
|
||||
1,
|
||||
[
|
||||
for (final item in _result)
|
||||
TraceLocation(
|
||||
latitude: item.latitude,
|
||||
longitude: item.longitude,
|
||||
speed: 32,
|
||||
bearing: 0,
|
||||
time: 60000,
|
||||
),
|
||||
],
|
||||
onTraceFinished: (List<LatLng> traceList, int distance) async {
|
||||
await _controller
|
||||
.addPolyline(PolylineOption(coordinateList: traceList));
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text('开始纠偏'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
41
example/lib/map/tools/static_image.screen.dart
Normal file
41
example/lib/map/tools/static_image.screen.dart
Normal file
@ -0,0 +1,41 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:amap_map_fluttify/amap_map_fluttify.dart';
|
||||
import 'package:decorated_flutter/decorated_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StaticImageScreen extends StatefulWidget {
|
||||
@override
|
||||
_StaticImageScreenState createState() => _StaticImageScreenState();
|
||||
}
|
||||
|
||||
class _StaticImageScreenState extends State<StaticImageScreen> {
|
||||
late Uint8List _imageData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('调用高德地图')),
|
||||
body: Center(
|
||||
child: DecoratedColumn(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
AmapService.instance
|
||||
.fetchStaticMapImage(LatLng(30, 120))
|
||||
.then((value) {
|
||||
setState(() {
|
||||
_imageData = value;
|
||||
});
|
||||
});
|
||||
},
|
||||
child: Text('获取静态图'),
|
||||
),
|
||||
if (_imageData != null) Image.memory(_imageData),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user