未经本人同意,禁止转载!
前几天开发flutter百度地图,总算是把第一步走通了,这几天把定位功能开发了一下。记录一下,所谓取之于CSDN用之于CSDN。
下面描述的工程是配置Android的,ios并没有配置。
开发环境:sdk: “>=2.12.0 < 3.0.0”
Android Studio版本3.4.0
文章目录
- 前言
- 一、引入官网的集成百度地图定位Flutter插件
- 二、导入dart类,使用对外接口
- 三、创建主界面代码
- 四、启动定位
- 五、停止定位
- 六、动态申请定位权限,并进行监听
- 七、移动点定位
- 八、全部代码,可直接复制使用,已添加空安全检测
- 九、实现效果
- 十、总结
前言
前面地图的步骤,直接按照百度地图保姆级教程(1) 来进行地图的引入即可,包括AK秘钥的引入,地图的显示等,下面的教程都是基于上面的所有步骤完成,地图正确显示之后,才能够进行。在(1)的代码基础上进行添加。部分步骤可以直接按照官网提供的来
flutter sdk2.9.0之后都是支持空安全检测的。
一、引入官网的集成百度地图定位Flutter插件
定位插件引入就引入官网提供的最新版本的,不然可能会出现空安全检测的警告:
flutter_bmflocation: ^2.0.0-nullsafety.0
二、导入dart类,使用对外接口
import ‘package:flutter_bmflocation/bdmap_location_flutter_plugin.dart’;
import ‘package:flutter_bmflocation/flutter_baidu_location.dart’;
import ‘package:flutter_bmflocation/flutter_baidu_location_android_option.dart’;
import ‘package:flutter_bmflocation/flutter_baidu_location_ios_option.dart’;
三、创建主界面代码
使用stack组件进行层叠式布局,将开始定位和停止定位按钮叠加在地图上面。用于控制是否进行定位操作。没怎么调整样式,只是先实现的功能。
Scaffold(
body:Container(
width: screenSize.width,
height: screenSize.height,
child: Stack(
alignment:Alignment.center , //指定未定位或部分定位widget的对齐方式
children: <Widget>[
Container(
child:BMFMapWidget(
onBMFMapCreated: (controller) { // 创建mapView回调
onBMFMapCreated(controller);
},
mapOptions: initMapOptions(), // 设置map地图参数
),
),
Positioned( // 这部分是用来切换卫星地图和普通地图
top: 0.0,
child: mapTypeSelect(),
),
Positioned( // 这部分用来显示经纬度信息和时间信息,都可以自己随意定义
top: 50,
child:Row(
children: widgets,
),
),
Positioned(
top: 70,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new RaisedButton(
onPressed: _startLocation, // 控制开始定位
child: new Text('开始定位'),
color: Colors.blue,
textColor: Colors.white,
),
new Container(width: 20.0),
new RaisedButton(
onPressed: _stopLocation, // 控制停止定位
child: new Text('停止定位'),
color: Colors.blue,
textColor: Colors.white,
)
],
),
)
],
),
),
);
// 选择组件
Widget mapTypeSelect() {
return Container(
height: 50.00,
decoration: BoxDecoration(
color: Colors.blue,
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
///包裹子布局
mainAxisSize: MainAxisSize.max,
children: [
Radio(
///此单选框绑定的值 必选参数
value: 'false',
///当前组中这选定的值 必选参数
groupValue: _groupValue,
///点击状态改变时的回调 必选参数
onChanged: (v) {
myMapController?.updateMapOptions(BMFMapOptions(mapType: BMFMapType.Standard));
setState(() {
this._groupValue = v;
});
},
),
Text("普通地图",style: TextStyle(color: Colors.white))
],
),
Row(
///包裹子布局
mainAxisSize: MainAxisSize.max,
children: [
Radio(
///此单选框绑定的值 必选参数
value: 'true',
///当前组中这选定的值 必选参数
groupValue: _groupValue,
///点击状态改变时的回调 必选参数
onChanged: (v) {
myMapController?.updateMapOptions(BMFMapOptions(mapType: BMFMapType.Satellite));
setState(() {
this._groupValue = v;
});
},
),
Text("卫星地图",style: TextStyle(color: Colors.white))
],
),
]
),
);
}
四、启动定位
准备定位,配置Android端的定位参数
/// 设置android端和ios端定位参数
void _setLocOption() {
/// android 端设置定位参数
BaiduLocationAndroidOption androidOption = new BaiduLocationAndroidOption();
androidOption.setCoorType("bd09ll"); // 设置返回的位置坐标系类型
androidOption.setIsNeedAltitude(true); // 设置是否需要返回海拔高度信息
androidOption.setIsNeedAddres(true); // 设置是否需要返回地址信息
androidOption.setIsNeedLocationPoiList(true); // 设置是否需要返回周边poi信息
androidOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
androidOption.setIsNeedLocationDescribe(true); // 设置是否需要返回位置描述
androidOption.setOpenGps(true); // 设置是否需要使用gps
androidOption.setLocationMode(LocationMode.Hight_Accuracy); // 设置定位模式
androidOption.setScanspan(1000); // 设置发起定位请求时间间隔
Map androidMap = androidOption.getMap();
/// ios 端设置定位参数
BaiduLocationIOSOption iosOption = new BaiduLocationIOSOption();
iosOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
iosOption.setBMKLocationCoordinateType("BMKLocationCoordinateTypeBMK09LL"); // 设置返回的位置坐标系类型
iosOption.setActivityType("CLActivityTypeAutomotiveNavigation"); // 设置应用位置类型
iosOption.setLocationTimeout(10); // 设置位置获取超时时间
iosOption.setDesiredAccuracy("kCLLocationAccuracyBest"); // 设置预期精度参数
iosOption.setReGeocodeTimeout(10); // 设置获取地址信息超时时间
iosOption.setDistanceFilter(100); // 设置定位最小更新距离
iosOption.setAllowsBackgroundLocationUpdates(true); // 是否允许后台定位
iosOption.setPauseLocUpdateAutomatically(true); // 定位是否会被系统自动暂停
Map iosMap = iosOption.getMap();
_locationPlugin.prepareLoc(androidMap, iosMap);
}
/// 启动定位
void _startLocation() {
if (null != _locationPlugin) {
_setLocOption();
_locationPlugin.startLocation();
}
}
五、停止定位
/// 停止定位
void _stopLocation() {
if (null != _locationPlugin) {
_locationPlugin.stopLocation();
}
}
六、动态申请定位权限,并进行监听
在initState生命周期中,动态申请定位权限,然后对结果进行实时监听
@override
void initState() {
super.initState();
/// 动态申请定位权限
_locationPlugin.requestPermission();
/// 动态监听地图信息
_locationListener = _locationPlugin.onResultCallback().listen((Map<String, Object>? result){
setState(() {
print('更新了状态');
if (result != null) {
_loationResult = result;
}
});
});
}
七、移动点定位
// 移动点定位
void mapLocation(lat, lng) {
myMapController?.showUserLocation(true);
BMFCoordinate coordinate = BMFCoordinate(lat, lng); // 经纬度信息
BMFLocation location = BMFLocation( // 定位信息
coordinate: coordinate, // 经纬度
altitude: 0, // 海拔
horizontalAccuracy: 5, // 水平精确度
verticalAccuracy: -1.0, // 垂直精确度
speed: -1.0, // 速度
course: -1.0); // 航向
BMFUserLocation userLocation = BMFUserLocation( // 当前位置对象
location: location,
);
myMapController?.updateLocationData(userLocation); // 动态更新我的位置数据
BMFUserLocationDisplayParam displayParam = BMFUserLocationDisplayParam(
locationViewOffsetX: 0,
locationViewOffsetY: 0,
accuracyCircleFillColor: Colors.red,
accuracyCircleStrokeColor: Colors.blue,
isAccuracyCircleShow: true,
locationViewImage: 'assets/images/marker_point.png',
locationViewHierarchy: BMFLocationViewHierarchy.LOCATION_VIEW_HIERARCHY_TOP
);
myMapController?.updateLocationViewWithParam(displayParam); // 动态定制我的位置样式
}
上面的就是所有的步骤了,如果不想看步骤的,可以直接复制下面的代码,直接进行定位操作
八、全部代码,可直接复制使用,已添加空安全检测
地图中心的经纬度可以手动设置固定值,也可以使用定位产生的变化值。
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
import 'package:flutter_bmflocation/bdmap_location_flutter_plugin.dart';
import 'package:flutter_bmflocation/flutter_baidu_location.dart';
import 'package:flutter_bmflocation/flutter_baidu_location_android_option.dart';
import 'package:flutter_bmflocation/flutter_baidu_location_ios_option.dart';
//import 'package:flutter_baidu_mapapi_search/flutter_baidu_mapapi_search.dart';
//import 'package:flutter_map_blue/BaiduMapHelper.dart';
class TestBaiduMapPage extends StatefulWidget {
@override
_TestBaiduMapPageState createState() => _TestBaiduMapPageState();
}
class _TestBaiduMapPageState extends State<TestBaiduMapPage> {
var lat,lng;
Map<String, Object>? _loationResult;
BaiduLocation? _baiduLocation; // 定位结果
StreamSubscription<Map<String, Object>?>? _locationListener;// 事件监听
LocationFlutterPlugin _locationPlugin = new LocationFlutterPlugin();
BMFMapController? myMapController;
var _groupValue; // 权限选项
// 选择组件
Widget mapTypeSelect() {
return Container(
// width: 500.00,
height: 50.00,
decoration: BoxDecoration(
color: Colors.blue,
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
///包裹子布局
mainAxisSize: MainAxisSize.max,
children: [
Radio(
///此单选框绑定的值 必选参数
value: 'false',
///当前组中这选定的值 必选参数
groupValue: _groupValue,
///点击状态改变时的回调 必选参数
onChanged: (v) {
myMapController?.updateMapOptions(BMFMapOptions(mapType: BMFMapType.Standard));
setState(() {
this._groupValue = v;
});
},
),
Text("普通地图",style: TextStyle(color: Colors.white))
],
),
Row(
///包裹子布局
mainAxisSize: MainAxisSize.max,
children: [
Radio(
///此单选框绑定的值 必选参数
value: 'true',
///当前组中这选定的值 必选参数
groupValue: _groupValue,
///点击状态改变时的回调 必选参数
onChanged: (v) {
myMapController?.updateMapOptions(BMFMapOptions(mapType: BMFMapType.Satellite));
setState(() {
this._groupValue = v;
});
},
),
Text("卫星地图",style: TextStyle(color: Colors.white))
],
),
]
),
);
}
@override
void initState() {
super.initState();
/// 动态申请定位权限
_locationPlugin.requestPermission();
/// 动态监听地图信息
_locationListener = _locationPlugin.onResultCallback().listen((Map<String, Object>? result){
setState(() {
print('更新了状态');
if (result != null) {
_loationResult = result;
}
});
});
}
/// 设置android端和ios端定位参数
void _setLocOption() {
/// android 端设置定位参数
BaiduLocationAndroidOption androidOption = new BaiduLocationAndroidOption();
androidOption.setCoorType("bd09ll"); // 设置返回的位置坐标系类型
androidOption.setIsNeedAltitude(true); // 设置是否需要返回海拔高度信息
androidOption.setIsNeedAddres(true); // 设置是否需要返回地址信息
androidOption.setIsNeedLocationPoiList(true); // 设置是否需要返回周边poi信息
androidOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
androidOption.setIsNeedLocationDescribe(true); // 设置是否需要返回位置描述
androidOption.setOpenGps(true); // 设置是否需要使用gps
androidOption.setLocationMode(LocationMode.Hight_Accuracy); // 设置定位模式
androidOption.setScanspan(1000); // 设置发起定位请求时间间隔
Map androidMap = androidOption.getMap();
/// ios 端设置定位参数
BaiduLocationIOSOption iosOption = new BaiduLocationIOSOption();
iosOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
iosOption.setBMKLocationCoordinateType("BMKLocationCoordinateTypeBMK09LL"); // 设置返回的位置坐标系类型
iosOption.setActivityType("CLActivityTypeAutomotiveNavigation"); // 设置应用位置类型
iosOption.setLocationTimeout(10); // 设置位置获取超时时间
iosOption.setDesiredAccuracy("kCLLocationAccuracyBest"); // 设置预期精度参数
iosOption.setReGeocodeTimeout(10); // 设置获取地址信息超时时间
iosOption.setDistanceFilter(100); // 设置定位最小更新距离
iosOption.setAllowsBackgroundLocationUpdates(true); // 是否允许后台定位
iosOption.setPauseLocUpdateAutomatically(true); // 定位是否会被系统自动暂停
Map iosMap = iosOption.getMap();
_locationPlugin.prepareLoc(androidMap, iosMap);
}
/// 启动定位
void _startLocation() {
if (null != _locationPlugin) {
_setLocOption();
_locationPlugin.startLocation();
}
}
/// 停止定位
void _stopLocation() {
if (null != _locationPlugin) {
_locationPlugin.stopLocation();
}
}
void addMarker() {
/// 创建BMFMarker
BMFMarker marker = BMFMarker(
position: BMFCoordinate(自己的经度,自己的纬度),
title: 'flutterMaker',
identifier: 'flutter_marker',
icon: 'assets/images/marker_point.png'
);
/// 添加Marker
myMapController?.addMarker(marker);
}
// 移动点定位
void mapLocation(lat, lng) {
myMapController?.showUserLocation(true);
BMFCoordinate coordinate = BMFCoordinate(lat, lng); // 经纬度信息
BMFLocation location = BMFLocation( // 定位信息
coordinate: coordinate, // 经纬度
altitude: 0, // 海拔
horizontalAccuracy: 5, // 水平精确度
verticalAccuracy: -1.0, // 垂直精确度
speed: -1.0, // 速度
course: -1.0); // 航向
BMFUserLocation userLocation = BMFUserLocation( // 当前位置对象
location: location,
);
myMapController?.updateLocationData(userLocation); // 动态更新我的位置数据
BMFUserLocationDisplayParam displayParam = BMFUserLocationDisplayParam(
locationViewOffsetX: 0,
locationViewOffsetY: 0,
accuracyCircleFillColor: Colors.red,
accuracyCircleStrokeColor: Colors.blue,
isAccuracyCircleShow: true,
locationViewImage: 'assets/images/marker_point.png',
locationViewHierarchy: BMFLocationViewHierarchy.LOCATION_VIEW_HIERARCHY_TOP
);
myMapController?.updateLocationViewWithParam(displayParam); // 动态定制我的位置样式
}
/// 创建BMFMarker
BMFMarker marker = BMFMarker(
position: BMFCoordinate(自己的经度,自己的纬度),
title: 'flutterMaker',
identifier: 'flutter_marker',
icon: 'assets/images/BlueTooth.png');
/// 创建完成回调
void onBMFMapCreated(BMFMapController controller) {
myMapController = controller;
/// 地图加载回调
myMapController?.setMapDidLoadCallback(callback: () {
print('mapDidLoad-地图加载完成!!!');
// addMarker();
});
}
/// 设置地图参数
BMFMapOptions initMapOptions() {
BMFMapOptions mapOptions = BMFMapOptions(
center: BMFCoordinate(自己的经度,自己的纬度),
zoomLevel: 18,
changeCenterWithDoubleTouchPointEnabled:true,
gesturesEnabled:true ,
scrollEnabled:true ,
zoomEnabled: true ,
rotateEnabled :true,
compassPosition :BMFPoint(0,0) ,
showMapScaleBar:false ,
maxZoomLevel:20,
minZoomLevel:8,
trafficEnabled:true,
);
return mapOptions;
}
Widget _resultWidget(key, value, local) {
return new Container(
height: 20,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('$key:' ' $value' ' Time:$local',style: TextStyle(color: Colors.white),),
]
),
),
color: Colors.blue,
);
}
@override
Widget build(BuildContext context) {
List<Widget> widgets = []; /// 用来保存位置信息,然后
if (_loationResult != null) {
widgets.add(_resultWidget(_loationResult?['latitude'], _loationResult?['longitude'],_loationResult?['locTime']));
}
Size screenSize = MediaQuery.of(context).size;
if(_loationResult?['latitude'] != null&&_loationResult?['longitude'] != null){
print('组件刷新');
print(_loationResult?['latitude']);
print(_loationResult?['longitude']);
print(_loationResult?['locTime']);
mapLocation(_loationResult?['latitude'],_loationResult?['longitude']);
}
return Scaffold(
appBar: AppBar(
title: Text("flutter baidu map demo Test"),
),
body:Container(
width: screenSize.width,
height: screenSize.height,
child: Stack(
alignment:Alignment.center , //指定未定位或部分定位widget的对齐方式
children: <Widget>[
Container(
child:BMFMapWidget(
onBMFMapCreated: (controller) { // 创建mapView回调
onBMFMapCreated(controller);
},
mapOptions: initMapOptions(), // 设置map地图参数
),
),
Positioned(
top: 0.0,
child: mapTypeSelect(),
),
Positioned(
top: 50,
child:Row(
children: widgets,
),
),
Positioned(
top: 70,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new RaisedButton(
onPressed: _startLocation,
child: new Text('开始定位'),
color: Colors.blue,
textColor: Colors.white,
),
new Container(width: 20.0),
new RaisedButton(
onPressed: _stopLocation,
child: new Text('停止定位'),
color: Colors.blue,
textColor: Colors.white,
)
],
),
)
],
),
),
);
}
}
九、实现效果
具体的实现效果就如下图所示,经纬度信息我给抹掉了,地图为了防止看到具体定位,我就手动缩小了。
十、总结
上面的代码是基于空安全检测的,如果你的sdk版本比较低,不支持空安全检测的话,只需要将空安全检测的?去掉,然后通过null来进行检测就好了。如果大家有什么问题,可以在下面评论,需要源代码的话可留言。