安装依赖
安装高德定位 Flutter 插件,高德地图 Flutter 插件。定位和地图是分开的,不要混淆。
amap_flutter_base: 2.0.0
amap_flutter_location: 2.0.0
amap_flutter_map: 2.0.2
KEY
创建应用
根据插件Readme得知,我们需要前往高德地图开放平台 分别申请 Android 端和 iOS 端的 key。
调试版签名
注意生成的文件debug.keystore
位置和别名androiddebugkey
,密码我设置的是android
。
keytool -genkey -v -keystore debug.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias androiddebugkey
配置签名
android/app/build.gradle
signingConfigs {
debug {
//keystore中key的别名
keyAlias 'androiddebugkey'
//keystore中key的密码
keyPassword 'android'
//keystore的文件路径,可以是绝对路径也可以是相对路径
storeFile file('../debug.keystore')
//keystore的密码l
storePassword 'android'
}
}
buildTypes {
debug {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
继续使用命令查看刚刚生成的 debug 版签名。
keytool -list -v -keystore android/debug.keystore
发布版签名
keytool -genkey -v -keystore C:\Private\ParagramLife\Documents\Flutter\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
其中C:\Private\ParagramLife\Documents\Flutter\key.jks
指定存储 key 的位置。
继续使用命令查看刚刚生成的发布版签名,注意你的文件位置。
keytool -list -v -keystore C:\Private\ParagramLife\Documents\Flutter\key.jks
配置签名
android/app/build.gradle
创建一个名为 android/key.properties
的文件,其中包含对密钥库的引用:
storePassword=
keyPassword=
keyAlias=key
storeFile=C:/Private/ParagramLife/Documents/Flutter/key.jks
注意: 保持文件私密; 不要将它加入公共源代码控制中,编辑 .gitignore 文件追加
/android/key.properties
在gradle中配置签名
通过编辑 android/app/build.gradle
文件为您的应用配置签名
替换:
android {
为:
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
替换:
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
为:
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
现在,您的应用的release版本将自动进行签名。
到此为止我们获取到来发布版 SHA1和调试版 SHA1,android/app/src/main/AndroidManifest.xml
文件查看 App 包名,返回高德地图开放平台继续添加 key 。
笔者没有 IOS ,故略。
高德地图
Android平台请参考Android Sudio配置工程,iOS平台请参考ios安装地图SDK
首先下载高德地图 SDK
添加 jar 文件
复制 android/app/libs 文件夹。
添加权限
android/app/src/main/AndroidManifest.xml
package="com.locyin.flutter_locyin">
<!-- 获取错略位置 通过WiFi或移动基站的方式获取用户错略的经纬度信息,定位精度大概误差在30~1500米 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!--申请调用A-GPS模块-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!-- 获取精确位置 通过GPS芯片接收卫星的定位信息,定位精度达10米以内 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 获取WiFi状态 获取当前WiFi接入的状态以及WLAN热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 读取电话状态 访问电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 读外部存储的权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 写外部存储的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 获取网络信息状态,如当前的网络连接是否有效 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
修改配置
android/build.gradle
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
//关闭混淆, 否则在运行release包后可能出现运行崩溃, TODO后续进行混淆配置
minifyEnabled false //删除无用代码
shrinkResources false //删除无用资源
}
}
sourceSets {
main {
// 插件单独运行时必须使用下面的类库,和导航插件同时使用时要注释掉
jniLibs.srcDirs = ['libs']
}
}
·
·
·
dependencies {
//demo中引入高德地图SDK
implementation('com.amap.api:3dmap:7.7.0')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
按需引入
官方 SDK 不支持空安全,我做了修改。
地图配置信息文件
lib/page/Map/const_config.dart
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:flutter/material.dart';
import 'package:flutter_locyin/utils/getx.dart';
import 'package:flutter_locyin/utils/toast.dart';
import 'package:permission_handler/permission_handler.dart';
import 'const_config.dart';
import 'package:get/get.dart' as getx;
class MapPage extends StatefulWidget {
MapPage({Key? key}) : super(key: key);
@override
MapPageState createState() => MapPageState();
}
class MapPageState extends State<MapPage> {
//默认显示在北京天安门
static final CameraPosition _kInitialPosition = const CameraPosition(
target: LatLng(39.909187, 116.397451),
zoom: 10.0,
);
///地图类型
MapType _mapType = MapType.normal;
///显示路况开关
bool _trafficEnabled = true;
/// 地图poi是否允许点击
bool _touchPoiEnabled = true;
///是否显示3D建筑物
bool _buildingsEnabled = true;
///是否显示底图文字标注
bool _labelsEnabled = true;
///是否显示指南针
bool _compassEnabled = true;
///是否显示比例尺
bool _scaleEnabled = true;
///是否支持缩放手势
bool _zoomGesturesEnabled = true;
///是否支持滑动手势
bool _scrollGesturesEnabled = true;
///是否支持旋转手势
bool _rotateGesturesEnabled = true;
///是否支持倾斜手势
bool _tiltGesturesEnabled = true;
///自定义定位小蓝点
MyLocationStyleOptions _myLocationStyleOptions = MyLocationStyleOptions(false);
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);
late AMapController _mapController;
String? _currentZoom;
final List<Permission> needPermissionList = [
Permission.location,
Permission.storage,
Permission.phone,
];
//需要先设置一个空的map赋值给AMapWidget的markers,否则后续无法添加marker
final Map<String, Marker> _markers = <String, Marker>{};
void _checkPermissions() async {
Map<Permission, PermissionStatus> statuses =
await needPermissionList.request();
statuses.forEach((key, value) {
print('$key premissionStatus is $value');
});
}
@override
void initState() {
super.initState();
_checkPermissions();
}
@override
void reassemble() {
super.reassemble();
_checkPermissions();
}
@override
Widget build(BuildContext context) {
final AMapWidget amap = AMapWidget(
apiKey: ConstConfig.amapApiKeys,
onMapCreated: _onMapCreated,
onCameraMove: _onCameraMove,
onCameraMoveEnd: _onCameraMoveEnd,
initialCameraPosition: _kInitialPosition,
mapType: _mapType,
trafficEnabled: _trafficEnabled,
buildingsEnabled: _buildingsEnabled,
compassEnabled: _compassEnabled,
labelsEnabled: _labelsEnabled,
scaleEnabled: _scaleEnabled,
touchPoiEnabled: _touchPoiEnabled,
rotateGesturesEnabled: _rotateGesturesEnabled,
scrollGesturesEnabled: _scrollGesturesEnabled,
tiltGesturesEnabled: _tiltGesturesEnabled,
zoomGesturesEnabled: _zoomGesturesEnabled,
customStyleOptions: _customStyleOptions,
myLocationStyleOptions: _myLocationStyleOptions,
onLocationChanged: _onLocationChanged,
onTap: _onMapTap,
onLongPress: _onMapLongPress,
onPoiTouched: _onMapPoiTouched,
//创建地图时,给marker属性赋值一个空的set,否则后续无法添加marker
markers: Set<Marker>.of(_markers.values),
);
return ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Column(
children: [
ConstrainedBox(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
minHeight: MediaQuery.of(context).size.height - 64),
child: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height - 64,
width: MediaQuery.of(context).size.width,
child: amap,
),
Positioned(
right: -10,
bottom: 132,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.add,
),
),
onPressed: _zoomIn,
),
)),
Positioned(
right: -10,
bottom: 72,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.remove,
),
),
onPressed: _zoomOut,
),
)
),
Positioned(
left: -10,
bottom: 72,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.location_on_outlined,
),
),
onPressed: _changeLatLngBounds,
),
)
),
Positioned(
left: -10,
bottom: 132,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.settings,
),
),
onPressed: () {},
),
)),
Positioned(
left: MediaQuery.of(context).size.width / 2 - 45,
bottom: 24,
child: ClipPath(
//路径裁切组件
clipper: CurveClipper(), //路径
child: ElevatedButton(
onPressed: _goDynamicPostPage,
child: SizedBox(
child: Column(
children: [
SizedBox(
height: 30,
),
Expanded(
child: Icon(
Icons.send,
),
),
Expanded(
child: Text(
"发布游记",
style: TextStyle(
fontSize: 14,
),
),
),
],
),
width: 60,
height: 100,
),
),
),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
color: Colors.grey,
padding: EdgeInsets.all(5),
alignment: Alignment.centerLeft,
child: Text(
_currentZoom.toString(),
),
),
),
],
),
),
],
));
}
//创建地图回调
void _onMapCreated(AMapController controller) {
_mapController = controller;
}
//移动视野
void _onCameraMove(CameraPosition cameraPosition) {}
//移动地图结束
void _onCameraMoveEnd(CameraPosition cameraPosition) {
setState(() {
_currentZoom = '当前缩放级别:${cameraPosition.zoom}';
});
}
//移动地图中心点位置
void _changeCameraPosition() {
_mapController.moveCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
//中心点
target: LatLng(31.230378, 121.473658),
//缩放级别
zoom: 13,
//俯仰角0°~45°(垂直与地图时为0)
tilt: 30,
//偏航角 0~360° (正北方为0)
bearing: 0),
),
animated: true,
);
}
//改变显示级别
void _changeCameraZoom() {
_mapController.moveCamera(
CameraUpdate.zoomTo(18),
animated: true,
);
}
//级别加1
void _zoomIn() {
_mapController.moveCamera(
CameraUpdate.zoomIn(),
animated: true,
);
}
//级别减1
void _zoomOut() {
_mapController.moveCamera(
CameraUpdate.zoomOut(),
animated: true,
);
}
//改变显示区域
void _changeLatLngBounds() {
_mapController.moveCamera(
CameraUpdate.newLatLngBounds(
LatLngBounds(
southwest: LatLng(33.789925, 104.838326),
northeast: LatLng(38.740688, 114.647472)),
15.0),
animated: true,
);
}
//移动地图到定位位置
void _mineLocation(double latitude, double longitude) {
_mapController.moveCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
//中心点
target: LatLng(latitude, longitude),
//缩放级别
zoom: 18,
//俯仰角0°~45°(垂直与地图时为0)
tilt: 30,
//偏航角 0~360° (正北方为0)
bearing: 0),
),
animated: true,
);
}
//按照像素移动
void _scrollBy() {
_mapController.moveCamera(
CameraUpdate.scrollBy(50, 50),
animated: true,
duration: 1000,
);
}
void _onLocationChanged(AMapLocation location) {
if (null == location) {
return;
}
print('_onLocationChanged ${location.toJson()}');
}
void _onMapTap(LatLng latLng) {
if (null == latLng) {
return;
}
print('_onMapTap===> ${latLng.toJson()}');
}
void _onMapLongPress(LatLng latLng) {
if (null == latLng) {
return;
}
print('_onMapLongPress===> ${latLng.toJson()}');
}
Widget showPoiInfo(AMapPoi poi) {
return Container(
alignment: Alignment.center,
color: Color(0x8200CCFF),
child: Text(
'您选择了 ${poi.name}',
style: TextStyle(fontWeight: FontWeight.w600),
),
);
}
void _onMapPoiTouched(AMapPoi poi) {
print(poi);
}
//跳转到游记发布页
void _goDynamicPostPage() {
ToastUtils.success('跳转到游记发布页');
}
}
/// 曲线路径裁剪
class CurveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path()..lineTo(0, 40);
var firstControlPoint = Offset(size.width / 2, 0);
var firstEdnPoint = Offset(size.width, 40);
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstEdnPoint.dx, firstEdnPoint.dy);
path..lineTo(size.width, size.height)..lineTo(0, size.height);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
截图
到这里代码全部都是高德地图SDK相关,没有和项目相关的代码,如果想移植其他项目中复制粘贴就可以直接使用,之后我会添加一些自定义逻辑,比如自动定位,添加标记,地图选点,会涉及到状态管理。
高德定位
首先下载高德定位官方 Fluter SDK
配置
设置Android和iOS的apiKey,如果这里不配置 key,也可以在后面定位服务lib/utils/location_based_service.dart
内通过AMapFlutterLocation.setApiKey("617d99f861823395679068efa584d09a", "");
配置,注意,后者的优先级更高。
android/app/src/main/AndroidManifest.xml
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="617d99f861823395679068efa584d09a" />
<!-- 配置定位Service -->
<service android:name="com.amap.api.location.APSService"/>
<activity
配置依赖
android/app/build.gradle
dependencies {
//demo中引入高德地图SDK
implementation('com.amap.api:3dmap:7.7.0')
implementation('com.amap.api:location:5.2.0')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
状态管理
为了实时更新地图视图的用户位置,我们把定位结果数据使用 Getx 状态管理。
lib/utils/getx.dart
// 用户信息状态控制器
class UserController extends GetxController{
Map<String, Object>? _location;
Map<String, Object>? get location => _location;
·
·
·
void updateLocation(Map<String, Object>? loc){
_location= loc;
print("更新位置视图");
update(['location']);
}
}
定位服务
我直接将定位服务封装在了 lib/widgets/locator.dart 内,为了节约资源,这里只使用单次定位。触发返回结果回调时更新 Getx 用户控制器UserController
内的用户位置信息location
。
lib/utils/location_based_service.dart
import 'dart:async';
import 'dart:io';
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
import 'package:flutter_locyin/utils/getx.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:get/get.dart';
class LocationBasedService {
static final _instance = LocationBasedService._internal();
//借助工厂模式实现单例模式
factory LocationBasedService() {
return _instance;
}
LocationBasedService._internal(){
_init();
}
Map<String, Object>? _locationResult;
AMapFlutterLocation _locationPlugin = new AMapFlutterLocation();
_init(){
/// 动态申请定位权限
_requestPermission();
///设置Android和iOS的apiKey<br>
///
/// 定位Flutter插件提供了单独的设置ApiKey的接口,
/// 使用接口的优先级高于通过Native配置ApiKey的优先级(通过Api接口配置后,通过Native配置文件设置的key将不生效),
/// 使用时可根据实际情况决定使用哪种方式
///
///key的申请请参考高德开放平台官网说明<br>
///
///Android: https://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key
///
///iOS: https://lbs.amap.com/api/ios-location-sdk/guide/create-project/get-key
//AMapFlutterLocation.setApiKey("617d99f861823395679068efa584d09a", "");
///iOS 获取native精度类型
if (Platform.isIOS) {
requestAccuracyAuthorization();
}
///注册定位结果监听
_locationPlugin
.onLocationChanged()
.listen((Map<String, Object> result) {
print("获取到定位信息:");
print(result);
_locationResult = result;
if(_locationResult!=null){
Get.find<UserController>().updateLocation(_locationResult);
}
});
}
///设置定位参数
void _setLocationOption() {
AMapLocationOption locationOption = new AMapLocationOption();
///是否单次定位
locationOption.onceLocation = true;
///是否需要返回逆地理信息
locationOption.needAddress = true;
///逆地理信息的语言类型
locationOption.geoLanguage = GeoLanguage.DEFAULT;
locationOption.desiredLocationAccuracyAuthorizationMode =
AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
locationOption.fullAccuracyPurposeKey = "AMapLocationScene";
///设置Android端连续定位的定位间隔
locationOption.locationInterval = 2000;
///设置Android端的定位模式<br>
///可选值:<br>
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
///设置iOS端的定位最小更新距离<br>
locationOption.distanceFilter = -1;
///设置iOS端期望的定位精度
/// 可选值:<br>
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
locationOption.desiredAccuracy = DesiredAccuracy.Best;
///设置iOS端是否允许系统暂停定位
locationOption.pausesLocationUpdatesAutomatically = false;
///将定位参数设置给定位插件
_locationPlugin.setLocationOption(locationOption);
}
///开始定位
void startLocation() {
_setLocationOption();
_locationPlugin.startLocation();
}
///停止定位
void stopLocation() {
_locationPlugin.stopLocation();
}
///获取iOS native的accuracyAuthorization类型
void requestAccuracyAuthorization() async {
AMapAccuracyAuthorization currentAccuracyAuthorization =
await _locationPlugin.getSystemAccuracyAuthorization();
if (currentAccuracyAuthorization ==
AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
print("精确定位类型");
} else if (currentAccuracyAuthorization ==
AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
print("模糊定位类型");
} else {
print("未知定位类型");
}
}
/// 动态申请定位权限
void _requestPermission() async {
// 申请权限
bool hasLocationPermission = await _requestLocationPermission();
if (hasLocationPermission) {
print("定位权限申请通过");
} else {
print("定位权限申请不通过");
}
}
/// 申请定位权限
/// 授予定位权限返回true, 否则返回false
Future<bool> _requestLocationPermission() async {
//获取当前的权限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已经授权
return true;
} else {
//未授权则发起一次申请
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
}
地图视图
引入定位服务类并实例化,开始定位。新增我的位置方法将地图中心点移动到用户所在经纬度,定位按钮绑定该方法。
lib/page/Map/map.dart
import 'package:flutter_locyin/utils/location_based_service.dart';
·
·
·
class MapPageState extends State<MapPage> {
//实例化定位服务类
var _locator = new LocationBasedService();
@override
void initState() {
super.initState();
_checkPermissions();
//开始定位
_locator.startLocation();
}
·
·
·
//定位按钮
Positioned(
left: -10,
bottom: 72,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.location_on_outlined,
),
),
onPressed: (){if (getx.Get.find<UserController>().location != null) {
_mineLocation(
double.parse(
getx.Get.find<UserController>().location!["latitude"].toString()),
double.parse(getx.Get.find<UserController>().location!["longitude"]
.toString()));
}else{
ToastUtils.error("没有获取到定位信息");
}
},
),
)
),
·
·
·
//我的位置
void _mineLocation(double latitude,double longitude){
_mapController.moveCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
//中心点
target: LatLng(latitude, longitude),
//缩放级别
zoom: 13,
//俯仰角0°~45°(垂直与地图时为0)
tilt: 30,
//偏航角 0~360° (正北方为0)
bearing: 0),
),
animated: true,
);
}
自动定位
现在是用户点击按钮后才进行地图的移动,我们希望获取到定位信息后立刻移动,Getx 用户控制器已经通知视图刷新(生产者),我们需要完成视图消费者,_initMineLocation 判断是否已经初始化用户位置了,防止视图刷新时重复移动。
lib/page/Map/map.dart
如果定位信息controller.location
不为空,则移动地图。
·
·
·
final List<Permission> needPermissionList = [
Permission.location,
Permission.storage,
Permission.phone,
];
bool _initMineLocation = false;
·
·
·
//缩放减1按钮
Positioned(
right: -10,
bottom: 72,
child: ClipPath.shape(
shape: StadiumBorder(),
child: ElevatedButton(
child: SizedBox(
width: 60,
height: 40,
child: Icon(
Icons.remove,
),
),
onPressed: _zoomOut,
),
)
),
//自动定位
getx.GetBuilder<UserController>(
init: UserController(),
id: "location",
builder: (controller) {
if (controller.location != null &&
(_initMineLocation == false)) {
_mineLocation(
double.parse(
controller.location!["latitude"].toString()),
double.parse(controller.location!["longitude"]
.toString()));
_initMineLocation = true;
}
return Container();
}),
添加标记
给用户地图上的位置添加一个 marker ,我们在地图初始化的时候已经设置了标记 map 映射,只需要在获取用户定位信息后,向 map 追加然后刷新 Widget 树即可。
//需要先设置一个空的map赋值给AMapWidget的markers,否则后续无法添加marker
final Map<String, Marker> _markers = <String, Marker>{};
_drawMineLocationMarker
记录是否已添加 marker ,如果没有添加一个 _addMarker 方法是高德地图 SDK 提供的。
bool _initMineLocation = false;
bool _drawMineLocationMarker = false;
//添加一个marker
void _addMarker() {
final _markerPosition = LatLng(
double.parse(
getx.Get.find<UserController>().location!['latitude'].toString()),
double.parse(
getx.Get.find<UserController>().location!['longitude'].toString()));
final Marker marker = Marker(
position: _markerPosition,
//使用默认hue的方式设置Marker的图标
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange),
);
//调用setState触发AMapWidget的更新,从而完成marker的添加
setState(() {
//将新的marker添加到map里
_markers[marker.id] = marker;
});
}
//移动地图结束
void _onCameraMoveEnd(CameraPosition cameraPosition) {
setState(() {
_currentZoom = '当前缩放级别:${cameraPosition.zoom}';
});
if (!_drawMineLocationMarker) {
_addMarker();
_drawMineLocationMarker = true;
}
}
定位、镜头移动和缩放一切正常,其他功能读者可以根据高德地图 Flutter 官方 SDK 自行定制。
版本提交
git add -A
git commit -m "高德定位、高德地图"