Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_百度地图polyline和轨迹-程序员宅基地

技术标签: 百度  android  android百度地图SDK  

上篇文章讲述了如何在地图显示位置点,这篇文章主要讲述如何在地图上画运动轨迹,以及地图图层点击事件的处理。

很多运动类的app都有画出跑步者运动轨迹的需求,拿咕咚来说,我们看一下它的效果图:

                           
                                                  运动轨迹图


本篇将要实现的效果
1.跑步结束后,静态的画出整个运动轨迹
2.跑步过程中,时时动态的画运动轨迹

                             


如何实现:
1.将点与点连成线,在百度地图MapView上画出线条图层;
2.获取定位点List<LatLng>:通过百度定位sdk:LocationClient类获取,户外运动画运动轨迹,要求位置点的精度高,所以我们必须使用gps定位类型的位置结果。


//允许使用gps定位
mOption.setOpenGps(true);

更多百度定位sdk参数详解请阅读篇头百度地图(一)文章

一 静态画整个运动轨迹

1.画轨迹


//伪代码
public void onCreate(){
  // 地图初始化
  MapView mMapView = (MapView) findViewById(R.id.bmapView);
  BaiduMap mBaiduMap = mMapView.getMap();
  // 开启定位图层
  mBaiduMap.setMyLocationEnabled(true);

  //获取运动后的定位点
  coordinateConvert();

  //设置缩放中点LatLng target,和缩放比例          
  MapStatus.Builder builder = new MapStatus.Builder();
  builder.target(target).zoom(18f);

  //地图设置缩放状态
  mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));

  /**
  * 配置线段图层参数类: PolylineOptions
  * ooPolyline.width(13):线宽
  * ooPolyline.color(0xAAFF0000):线条颜色红色
  * ooPolyline.points(latLngs):List<LatLng> latLngs位置点,将相邻点与点连成线就成了轨迹了
  */
  OverlayOptions ooPolyline = new PolylineOptions().width(13).color(0xAAFF0000).points(latLngs);

  //在地图上画出线条图层,mPolyline:线条图层
  mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
  mPolyline.setZIndex(3);
}

/**
 * 我这里是在google地图取下来的wgs84坐标集合Const.googleWGS84,模拟的运动后获取的坐标集合,
   所以需要转化成百度坐标;实际应该是将定位sdk返回的位置点加入到位置集合中,
   定位sdk需要设置返回坐标为百度坐标:mOption.setCoorType("bd09ll"),这样就直接用,不用转换了。
 */
private void  coordinateConvert(){
  //百度坐标转化工具类CoordinateConverter 
  CoordinateConverter converter  = new CoordinateConverter(); 

  /**
  * 设置需要转化的坐标类型
    CoordType.COMMON:google地图、腾讯地图、高德地图所用坐标
    CoordType.GPS:设备采集的原始GPS坐标
  */
  converter.from(CoordType.COMMON);

  double lanSum = 0;
  double lonSum = 0;
  for (int i = 0; i < Const.googleWGS84.length; i++) {
    //"39.881970,116.456218"
    String[] ll = Const.googleWGS84[i].split(",");
    LatLng sourceLatLng = new LatLng(Double.valueOf(ll[0]), Double.valueOf(ll[1]));
    converter.coord(sourceLatLng);  //需要转化的坐标点
    LatLng desLatLng = converter.convert();  //转化成百度坐标点
    latLngs.add(desLatLng);//加入定位点集合
    lanSum += desLatLng.latitude;
    lonSum += desLatLng.longitude;
  }

  //我这里设置地图的缩放中心点为所有点的几何中心点
  target = new LatLng(lanSum/latLngs.size(), lonSum/latLngs.size());
}

运动轨迹效果

                                 


2.添加起始图标图层、点击图层响应事件


//始点图层图标
BitmapDescriptor startBD= BitmapDescriptorFactory
            .fromResource(R.drawable.ic_me_history_startpoint);
//终点图层图标
BitmapDescriptor finishBD= BitmapDescriptorFactory
            .fromResource(R.drawable.ic_me_history_finishpoint);

//地图中显示信息窗口
InfoWindow mInfoWindow;

MarkerOptions oStart = new MarkerOptions();//地图标记类型的图层参数配置类 
oStart.position(latLngs.get(0));//图层位置点,第一个点为起点
oStart.icon(startBD);//设置图层图片
oStart.zIndex(1);//设置图层Index
//添加起点图层
Marker mMarkerA = (Marker) (mBaiduMap.addOverlay(oStart)); 

//添加终点图层
MarkerOptions oFinish = new MarkerOptions().position(latLngs.get(latLngs.size()-1)).icon(finishBD).zIndex(2);
Marker mMarkerB = (Marker) (mBaiduMap.addOverlay(oFinish));

//设置图层点击监听回调
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {
  public boolean onMarkerClick(final Marker marker) {
    if (marker.getZIndex() == mMarkerA.getZIndex() ) {
    //如果是起始点图层
      TextView textView = new TextView(getApplicationContext());
      textView.setText("起点");
      textView.setTextColor(Color.BLACK);
      textView.setGravity(Gravity.CENTER);
      textView.setBackgroundResource(R.drawable.popup);

      //设置信息窗口点击回调
      OnInfoWindowClickListener listener = new OnInfoWindowClickListener() {
        public void onInfoWindowClick() {
          //这里是主线线程,可以实现自己的一些功能
          Toast.makeText(getApplicationContext(),"这里是起点", Toast.LENGTH_SHORT).show();
          mBaiduMap.hideInfoWindow();//隐藏信息窗口
        }
      };

      LatLng latLng = marker.getPosition();//信息窗口显示的位置点

      /**
      * 通过传入的 bitmap descriptor 构造一个 InfoWindow
      * bd - 展示的bitmap
        position - InfoWindow显示的位置点
        yOffset - 信息窗口会与图层图标重叠,设置Y轴偏移量可以解决
        listener - 点击监听者
      */
      mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(textView), latLng, -47, listener);
      mBaiduMap.showInfoWindow(mInfoWindow);//显示信息窗口
    } else if (marker.getZIndex() == mMarkerB.getZIndex()) {
    //如果是终点图层
      Button button = new Button(getApplicationContext());
      button.setText("终点");
      button.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
          Toast.makeText(getApplicationContext(),"这里是终点", Toast.LENGTH_SHORT).show();
          mBaiduMap.hideInfoWindow();
        }
      });

      LatLng latLng = marker.getPosition();
      /**
      * 通过传入的 view 构造一个 InfoWindow, 此时只是利用该view生成一个Bitmap绘制在地图中,监听事件由自己实现。
        view - 展示的 view
        position - 显示的地理位置
        yOffset - Y轴偏移量
      */
      mInfoWindow = new InfoWindow(button, latLng, -47);
      mBaiduMap.showInfoWindow(mInfoWindow);
    } 
    return true;
 }
});

//也可以给运动轨迹添加点击事件
mBaiduMap.setOnPolylineClickListener(new BaiduMap.OnPolylineClickListener() {
  @Override
  public boolean onPolylineClick(Polyline polyline) {
    if (polyline.getZIndex() == mPolyline.getZIndex()) {
      Toast.makeText(getApplicationContext(),"点数:" + polyline.getPoints().size() + ",width:" + polyline.getWidth(), Toast.LENGTH_SHORT).show();
    }
    return false;
  }
});

运动轨迹效果,点击图标弹出信息窗口

             
点击                    起始图标


            点击图标弹出信息窗口弹出Toast

                      


                  到这里,运动结束后画出整个轨迹图和图层添加点击事件就介绍完了。

二 时时动态的画运动轨迹

时时动态画运动轨迹效果

                            
运动                 轨迹:箭头为当前位置和方向


关键在于取点:gps刚接收到信号时返回的一些点精度不高,容易造成位置偏移,如何取点很重要。


//伪代码
public void onCreate() {
  mMapView = (MapView) findViewById(R.id.bmapView);
  mBaiduMap = mMapView.getMap();
  // 开启定位图层
  mBaiduMap.setMyLocationEnabled(true);

  /**添加地图缩放状态变化监听,当手动放大或缩小地图时,拿到缩放后的比例,然后获取到下次定位,
  *  给地图重新设置缩放比例,否则地图会重新回到默认的mCurrentZoom缩放比例
  */
  mCurrentZoom = 18;
  mBaiduMap.setOnMapStatusChangeListener(new OnMapStatusChangeListener() {
    @Override
    public void onMapStatusChangeStart(MapStatus arg0) {
    }

    @Override
    public void onMapStatusChangeFinish(MapStatus arg0) {
      mCurrentZoom = arg0.zoom;//获取手指缩放地图后的值
    }

    @Override
    public void onMapStatusChange(MapStatus arg0) {
    }
  });

  //设置定位图标类型为跟随模式
  mBaiduMap.setMyLocationConfiguration(new MyLocationConfiguration(
                com.baidu.mapapi.map.MyLocationConfiguration.LocationMode.FOLLOWING, true, null));

  // 定位初始化
  mLocClient = new LocationClient(this);
  mLocClient.registerLocationListener(myListener);
  LocationClientOption option = new LocationClientOption();
  option.setLocationMode(LocationMode.Device_Sensors);//只接受gps位置
  option.setOpenGps(true); // 允许gps定位
  option.setCoorType("bd09ll"); // 设置坐标类型
  option.setScanSpan(1000);//一秒一个gps
  mLocClient.setLocOption(option);
}

//开始获取位置点
public void onStart() {
  start.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        if (mLocClient != null && !mLocClient.isStarted()) {
            mLocClient.start();
        }
    }
  });
}

//位置回调,取点很重要
public class MyLocationListenner implements BDLocationListener {

    @Override
    public void onReceiveLocation(final BDLocation location) {

        if (location == null || mMapView == null) {
            return;
        }

        if (location.getLocType() == BDLocation.TypeGpsLocation) {
    //只要gps点

            if (isFirstLoc) {
    //首次定位
                /**第一个点很重要,决定了轨迹的效果,gps刚接收到信号时返回的一些点精度不高,
                * 尽量选一个精度相对较高的起始点,这个过程大概从gps刚接收到信号后5-10秒就可以完成,不影响效果。
                * 注:gps接收卫星信号少则十几秒钟,多则几分钟,
                * 如果长时间手机收不到gps,退出,重启手机再试,这是硬件的原因
                */
                LatLng ll = null;

                //选一个精度相对较高的起始点
                ll = getMostAccuracyLocation(location);
                if(ll == null){
                    return;
                }
                isFirstLoc = false;
                points.add(ll);//加入集合
                last = ll;

                //显示当前定位点,缩放地图
                locateAndZoom(location, ll);

                //标记起点图层位置
                MarkerOptions oStart = new MarkerOptions();// 地图标记覆盖物参数配置类
                oStart.position(points.get(0));// 覆盖物位置点,第一个点为起点
                oStart.icon(startBD);// 设置覆盖物图片
                mBaiduMap.addOverlay(oStart); // 在地图上添加此图层
                return;//画轨迹最少得2个点,首地定位到这里就可以返回了
            }

            //从第二个点开始
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
            //sdk回调gps位置的频率是1秒1个,位置点太近动态画在图上不是很明显,可以设置点之间距离大于为5米才添加到集合中
            if (DistanceUtil.getDistance(last, ll) < 5) {
                return;
            }

            points.add(ll);//如果要运动完成后画整个轨迹,位置点都在这个集合中

            last = ll;

            //显示当前定位点,缩放地图
            locateAndZoom(location, ll);

            //清除上一次轨迹,避免重叠绘画
            mMapView.getMap().clear();

            //起始点图层也会被清除,重新绘画
            MarkerOptions oStart = new MarkerOptions();
            oStart.position(points.get(0));
            oStart.icon(startBD);
            mBaiduMap.addOverlay(oStart);

            //将points集合中的点绘制轨迹线条图层,显示在地图上
            OverlayOptions ooPolyline = new PolylineOptions().width(13).color(0xAAFF0000).points(points);
            mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
        }
    }
}

//首次定位很重要,选一个精度相对较高的起始点
private LatLng getMostAccuracyLocation(final BDLocation location){

    if (location.getRadius()>25) {
    //gps位置精度大于25米的点直接弃用
        return null;
    }

    LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());

    if (DistanceUtil.getDistance(last, ll ) > 5) {
        last = ll;
        points.clear();//有两点位置大于5,重新来过
        return null;
    }
    points.add(ll);
    last = ll;
    //有5个连续的点之间的距离小于5,认为gps已稳定,以最新的点为起始点
    if(points.size() >= 5){
        points.clear();
        return ll;
    }
    return null;
}

//显示当前定位点,缩放地图
private void locateAndZoom(BDLocation location, LatLng ll) {
    /**
    * 记录当前经纬度,当位置不变,手机转动,取得方向传感器的方向,
      给地图重新设置位置参数,在跟随模式下可使地图箭头随手机转动而转动
    */
    mCurrentLat = location.getLatitude();
    mCurrentLon = location.getLongitude();
    locData = new MyLocationData.Builder().accuracy(0)//去掉精度圈
            //此mCurrentDirection为自己获取到的手机传感器方向信息,顺时针0-360
            .direction(mCurrentDirection).latitude(location.getLatitude())
            .longitude(location.getLongitude()).build();
    mBaiduMap.setMyLocationData(locData);//显示当前定位位置点

    //给地图设置缩放中心点,和缩放比例值
    builder = new MapStatus.Builder();
    builder.target(ll).zoom(mCurrentZoom);
    mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
}

//运动结束增加终点图标
finish.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {

        if (mLocClient != null && mLocClient.isStarted()) {
            mLocClient.stop();//停止定位

            if(points.size() <= 0){
                return;
            }

            //运动结束记得标记终点图标
            MarkerOptions oFinish = new MarkerOptions();
            oFinish.position(points.get(points.size() - 1));
            oFinish.icon(finishBD);
            mBaiduMap.addOverlay(oFinish); 
        }
    }
});

退出记得释放资源


//伪代码
protected void onDestroy() {
  // 退出时销毁定位
  mLocClient.unRegisterLocationListener(myListener);
  mLocClient.stop();
  // 关闭定位图层
  mBaiduMap.setMyLocationEnabled(false);
  mMapView.getMap().clear();
  mMapView.onDestroy();
  mMapView = null;
  startBD.recycle();
  finishBD.recycle();
}

注:我们画运动轨迹要求定位sdk返回的位置精度很高,轨迹的效果才会好,因而必须接受gps位置点。但是gps位置的在刚开始收到信号时精度不高,会出现位置漂移的情况,所以要选取一个精度较好的点。在建筑物、桥梁、大树、隧道里面,gps信号不好,精度不高,所以在开阔地带,运动轨迹效果更好。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yangbin0513/article/details/74913958

智能推荐

【愚公系列】2023年10月 WPF控件专题 Popup控件详解_wpf popup-程序员宅基地

文章浏览阅读7.8k次,点赞4次,收藏6次。WPF控件是Windows Presentation Foundation(WPF)中的基本用户界面元素。它们是可视化对象,可以用来创建各种用户界面。WPF控件可以分为两类:原生控件和自定义控件。原生控件是由Microsoft提供的内置控件,如Button、TextBox、Label、ComboBox等。这些控件都是WPF中常见的标准用户界面元素。自定义控件则允许开发人员使用XAML和C#等编程语言来创建个性化的用户界面元素。自定义控件可以根据需求提供更多的功能和自定义化选项,以及更好的用户体验。_wpf popup

VM二次开发VM.PlatformSDKCS.VmException:“应用程序中的错误。”-程序员宅基地

文章浏览阅读72次。这是因为VM开发框架与你的目标框架不同导致,点击属性将目标框架切换到对应即可,如果不行就都试一遍,我这里是4.7.1,VM4.3,谢谢支持与点赞。

Elastic Job 同城主备、同城双活,高可用必备_es集群 双活方案-程序员宅基地

文章浏览阅读776次。在使用Elastic Job Lite做定时任务的时候,我发现很多开发的团队都是直接部署单点,这对于一些离线的非核心业务(如对账、监控等)或许无关紧要,但对于一些高可用补偿、核心数据定时修改(如金融场景的利息更新等),单点部署则“非常危险”。实际上,Elastic Job Lite是支持高可用的。网上关于Elastic Job的较高级的博文甚少,本文试图结合自身实践的一些经验,大致讲解其方案原理,并延伸至同城双机房的架构实践。单点部署到高可用如本文开头所说,很多系统的部署是采取以下部署架构:_es集群 双活方案

SAP ABAP 反查BOM, 找出它的上阶_abap bom反查至最上层-程序员宅基地

文章浏览阅读2.5k次。更多内容关注公众号:SAP Technical各位可以关注我的公众号:SAP Technical查询物料的上阶方法有三:1. CS15 可直接查出物料的上阶直至顶阶物料.2. CALL FUNCTION. 只能查上上阶, 要想得到顶阶, 需要递归查询.CS_WHERE_USED_MAT Bills of material; where-used li..._abap bom反查至最上层

JS(JavaScript)详解-程序员宅基地

文章浏览阅读7k次,点赞7次,收藏37次。JavaScript是由Netscape(网景)公司研发出来的一种在它的Navigator浏览器上执行的程序语言。JavaScript是一种基于对象(object-based)和事件驱动(Event Driven)的简单的并具有安全性能的脚本语言。JavaScript组成ECMAScript:JavaScript的核心,语法格式,使用方法文档对象模型(DOM,document object model):DOM(文档对象模型)是 HTML 和 XML 的应用程序接口(API)。_js

最好用的caffe深度学习简单批处理数据集(windows+linux+Python)_win linux 深度学习 数据集-程序员宅基地

文章浏览阅读395次。简单的批处理方式,包含了windows系统下的bat文件,Linux系统下的sh文件以及最牛逼的Python脚本。在进行AI相关的研究时,不可避免的需要去进行处理数据集。有些数据集是现成的,有些数据集却是需要自己去定制的。以下是自己在学习的过程中总结出来的比较常见的几种方式去处理数据。因为做的是CV,所以设计的处理方式多是处理图片。一、windows下的bat1、统计每个文件夹的名称以及相应文..._win linux 深度学习 数据集

随便推点

java计算机毕业设计随心淘网管理系统源代码+数据库+系统+lw文档-程序员宅基地

文章浏览阅读203次。java计算机毕业设计随心淘网管理系统源代码+数据库+系统+lw文档。springboot基于B_S架构的疫情包联信息管理系统的设计与实现。springboot基于精细化考核的离散数学课程教学目标达成系统。springboot基于Springboot的大学宿舍管理系统。ssm临港新片区招商引资项目管理系统的设计与实现。_jsp__access_在线网络购物系统_ssm疫情背景下基于web的学生信息日报系统。JSP广告公司网站的设计与实现mysql。jsp基于javaweb的公益募捐网站。

Oracle19c安装及监听配置&PLSQL Developer安装-程序员宅基地

文章浏览阅读233次。首先,在“开始”菜单栏中找到Oracle-OraDB19Home1(因安装版本不同可能会有差异),接着打开Net Configuration Assistant,进行监听程序的配置;使用dos命令(windows徽标+R--输入cmd)/菜单栏搜索框直接输入cmd,输入lsnrctl status;监听程序配置完成后再通过cmd输入lsnrctl status命令,测试如下则说明监听程序已配置完成;Oracle主目录用户口令即在下载Oracle时自定义的口令密码;若如下图显示则是尚未开启监听程序;

Java中8种常见的数据结构_java数据结构-程序员宅基地

文章浏览阅读152次。数组、链表、堆、栈、队列、树、哈希、图。_java数据结构

C11新特性-程序员宅基地

文章浏览阅读1.1k次。C++11常用特性总结1、关键字及新语法C++11相比C++98增加了许多关键字及新的语法特性,很多人觉得这些语法可有可无,没有新特性也可以用传统C++去实现。也许吧,但个人对待新技术总是抱着渴望而热衷的态度对待,也许正如很多人所想,用传统语法也可以实现,但新技术可以让你的设计更完美。这就如同在原来的维度里,你要完成一件事情,需要很多个复杂的步骤,但在新语法特性里,你可以从另外的维度,很干脆,直接就把原来很复杂的问题用很简单的方法解决了,我想着就是新的技术带来的一些编程体验上非常好的感觉。大家也不要觉_c11新特性

hive导入导出数据自动化的shell脚本_shell一个脚本同时导入导出数据-程序员宅基地

文章浏览阅读3.2k次。1.从mysql导入到hive的ods层的shell脚本传参表示要导入的数据分期日期,sqoop导入,实例:#!/bin/bashexport SQOOP_HOME=/usr/bin/sqoopif [ $# == 1 ] then dateStr=$1 else dateStr=`date -d '-1 day' +'%Y-%m-%d'`fidateNowStr=`date +'%Y-%m-%d'`yearStr=`date -d ${dateStr}_shell一个脚本同时导入导出数据

python 报错 被呼叫方拒绝接收呼叫_在对excel的操作中报错,被呼叫方拒绝接收呼叫...-程序员宅基地

文章浏览阅读1.1k次。-王大海 2009-03-12 06:25(二) 使用Delphi 控件方法在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWorksheet。1) 打开Excel :ExcelApplication1.Connect;2) 显示当前窗口:ExcelApplication1.Visible[0]:=True;3) 更改 ..._python win32 被呼叫方拒绝接收呼叫

推荐文章

热门文章

相关标签