Flutter开发百度地图之定位,保姆级教程(2)

未经本人同意,禁止转载!
前几天开发flutter百度地图,总算是把第一步走通了,这几天把定位功能开发了一下。记录一下,所谓取之于CSDN用之于CSDN。
下面描述的工程是配置Android的,ios并没有配置。
开发环境:sdk: “>=2.12.0 < 3.0.0”
Android Studio版本3.4.0


前言

前面地图的步骤,直接按照百度地图保姆级教程(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来进行检测就好了。如果大家有什么问题,可以在下面评论,需要源代码的话可留言。

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值