amap_map_fluttify

This commit is contained in:
2024-11-17 15:45:43 +08:00
commit ee80f75473
554 changed files with 220726 additions and 0 deletions

View 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('停止定位'),
),
],
);
}
}

View 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()}');
},
),
],
),
),
],
),
);
}
}

View 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);
}
},
),
],
),
),
],
),
);
}
}

View 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();
},
),
],
),
),
],
),
);
}
}

View 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();
},
),
],
),
),
],
),
);
}
}

View 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();
}
}

View 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,
// ));
// },
// ),
],
),
),
],
),
);
}
}

View 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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View 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)
],
),
),
],
),
);
}
}

View 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 = '点击地图创建电子围栏';
});
}
}

View 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(),
// ),
// ],
// ),
],
);
}
}

View 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() + ''),
],
),
);
}
}

View 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'),
),
],
),
],
),
);
}
}

View 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('高德地图骑行导航'),
),
],
),
),
);
}
}

View File

@ -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(),
// );
// },
// ),
);
}
}

View File

@ -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();
}
}

View 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}';
}
}

View 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('离线地图管理'),
),
),
);
}
}

View 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('开始纠偏'),
),
],
),
);
}
}

View 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),
],
),
),
);
}
}