Flutter ----实现定位+范围限制(距离目的地1000米才能打卡)

需求:
1.实现设备的定位
2.当前位置和目标位置的1000米范围内才能打卡

该页面就是简单的进去的时候就获取定位,如果定位获取到了就停止定位,并toast是否可以打卡的消息。

采用的定位的插件:
flutter_bmflocation: ^2.0.0-nullsafety.0

##为什么使用百度地图的插件?而不是其他的插件
采用的是百度地图的插件,这个星期尝试了三个插件,第一个最先使用的location插件,不需要申请啥开发者啥的直接可以用的,但是悲哀的是时不时会失灵的,怀疑是网络问题,回调死活进不去。第二个尝试的是高德地图的,为什么呢,搜索的时候大家都用高德的,所以我也去试验了一下,但是高德地图明显很久没有维护了,现在flutter是空安全的,但是它明显是老的,不支持空安全,导致调试的时候非常麻烦,虽然可以用,但是为了以后方便还是被pass。然后选择了百度,明显百度有在维护,有支持空安全和不支持空安全的版本,所以选择了它。

##注意
当然使用百度地图的api,当然要去注册开发者申请一个应用,然后去申请AK这一系列麻烦的东西。
dart插件的例子
https://pub.dev/packages/flutter_bmflocation/example

百度定位的flutter的文档,照着来就行
https://lbsyun.baidu.com/index.php?title=flutter/loc
在这里插入图片描述

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:math';
import 'package:app_flutter/common/global.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.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';

class ImageUploadRoute extends StatefulWidget {
  ImageUploadRoute({Key? key, this.title}) : super(key: key);
  final String? title;
  @override
  _ImageUploadState createState() => _ImageUploadState();
}

class _ImageUploadState extends State<ImageUploadRoute> {
  //编辑文本
  late TextEditingController _controller;
  
  //定位相关
  double lat1=0.0;//当前的维度
  double lng1=0.0;//当前的经度
  double lat2=0.0;//目的地的维度
  double lng2=0.0;//目的地的经度
  int limitMmeters=1000;//限制上传的距离,一公里范围内
  late Map<String, Object>? _loationResult=null;
  BaiduLocation? _baiduLocation;
  late StreamSubscription<Map<String, Object>?> _locationListener;
  LocationFlutterPlugin _locationPlugin = new LocationFlutterPlugin();

  
  //初始化的时候打开定位相关
  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();

    /// 动态申请定位权限
    _locationPlugin.requestPermission();
    /// 设置ios端ak, android端ak可以直接在清单文件中配置
    LocationFlutterPlugin.setApiKey("jInwiO1AhcbkZyz0Z9ZL9fC88pThdGZP");

    _locationListener = _locationPlugin.onResultCallback().listen((Map<String, Object>? result) {
      setState(() {
        _loationResult = result;
        print("longitude$result['longitude']");
        try {
          _baiduLocation = BaiduLocation.fromMap(result);
          isInArea();
//          print(_baiduLocation);
        } catch (e) {
          print(e);
        }
      });
    });
    _startLocation();//开启位置监听
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
    if (null != _locationListener) {
      _locationListener.cancel();
    }
  }

  /// 设置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();
    }
  }





  double  _rad(double d) {
    return d * pi / 180.0;
  }
  double  _getDistance(double lat1, double lng1, double lat2, double lng2) {
    /// 单位:米
    /// def :地球半径
    double def = 6378137.0;
    double radLat1 = _rad(lat1);
    double radLat2 = _rad(lat2);
    double a = radLat1 - radLat2;
    double b = _rad(lng1) - _rad(lng2);
    double s = 2 * asin(sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2)));
    return (s * def ).roundToDouble();
  }


  //是否在范围内?
  void isInArea(){
    lat1=_baiduLocation?.latitude??0;//如果没值 那么0
    lng1=_baiduLocation?.longitude??0;//如果没值 那么0
    double distance=_getDistance(lat1,lng1,lat2,lng2);
    if(lat1!=0&&lng1!=0){//正确的获取到了坐标
      if(limitMmeters>=distance){//在范围内允许
        Global.showCenterToast("允许打卡");
        _stopLocation();
      }else{//在范围外
        Global.showCenterToast("不在范围内,当前距离目标位置$distance米,打卡范围为$limitMmeters米");
        _stopLocation();
      }
    }else{
      Global.showCenterToast("位置获取中!");
    }
  }


  //页面的控件布局
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("定位"),),
        body:Stack(
          children: [
            Positioned(//占满屏幕
                top: 0,
                bottom: 0,
                left: 0,
                right: 0,
                child: Column(
                  children: [
                    TextField(
                      maxLines: 10,
                      minLines: 3,
                      controller:_controller,
                      decoration:InputDecoration(
                        border:InputBorder.none ,
                        fillColor:Colors.white ,
                        filled: true,
                        hintText: "签收情况",
                      ),
                    ),
                  ],
                )),
          ],
        )

    );
  }

}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值