转载、引用请标明出处
http://www.jianshu.com/p/2ad4c2077dfd
本文出自zhh_happig的博客,谢谢

Android百度地图(一):百度地图定位sdk 类方法参数、定位原理详细介绍
Android百度地图(二):百度地图sdk显示位置点、图层绘制
Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼sdk服务
Android百度地图(五):百度地图鹰眼sdk监控进出地理围栏(区域)
Android百度地图(六):百度地图POI检索,行政区边界、公交、线路规划查询,地理编码介绍

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

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

Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第1张图片 咕咚运动轨迹图

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


Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第2张图片 效果图

如何实现:
1.将点与点连成线,在百度地图MapView上画出线条图层;
2.获取定位点List:通过百度定位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 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());}

运动轨迹效果

Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第3张图片 轨迹图
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 - 点击监听者        另外,Projection类可以将地理坐标和屏幕坐标进行相互转换。        Point point = mBaiduMap.getProjection().toScreenLocation(latLng)是        将地理坐标转换为屏幕上的坐标,其中point.y是地理位置点相对于MapView左上角的y轴坐标。        这里就可以将mInfoWindow放在你指定的y轴位置了,        如果将InfoWindow第三个参数设置为mMapView.getHeight()-point.y,        那么mInfoWindow是不是就放着屏幕底部了呢,哈哈。注意mMapView.getHeight()的取值时机。      */      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;  }});

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


Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第4张图片 点击起始图标

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

Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第5张图片 弹出Toast

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

二 时时动态的画运动轨迹

时时动态画运动轨迹效果


Android百度地图(三):百度地图画运动轨迹及图层点击事件处理_第6张图片 运动轨迹:箭头为当前位置和方向

关键在于取点: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;        }        //注意:这里只要gps点,需要在室外定        if (location.getLocType() == BDLocation.TypeGpsLocation) {                            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);        }    }}/*** 首次定位很重要,选一个精度相对较高的起始点* 注意:如果一直显示gps信号弱,说明过滤的标准过高了,  你可以将location.getRadius()>25中的过滤半径调大,比如>50,  并且将连续5个点之间的距离DistanceUtil.getDistance(last, ll ) > 5也调大一点,比如>10,  这里不是固定死的,你可以根据你的需求调整。*/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信号不好,精度不高,所以在开阔地带,运动轨迹效果更好。

当运动轨迹效果不佳时,可以利用百度鹰眼sdk采集位置数据,然后查询纠偏后轨迹,这样效果会好很多,详情请阅读:
Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼sdk服务

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

如果各位看官觉得文章不错,别忘了点个喜欢。
源码下载地址

以上文章内容,是本人工作中的总结,供大家参考,有误的地方还请指正。

更多相关文章

  1. Android百度地图(五):百度地图鹰眼sdk监控进出地理围栏(区域)
  2. Android实习笔记----调用拨号器,邮件短信和Google 地图
  3. Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰
  4. Android百度地图(一):百度地图定位sdk 类方法参数、定位原理详细
  5. Android百度地图导航的那些坑
  6. Android百度地图(六):百度地图POI检索,行政区边界、公交、线路规
  7. Android百度地图SDK—地图标记
  8. 【Arcgis for android】保存地图截图到sd卡
  9. Android使用百度地图移动到我的位置

随机推荐

  1. android之activity生命周期示例
  2. Android FragmentTabHost的简单使用
  3. Android SQLiteOpenHelper的使用
  4. Android/Eclipse Installation on Ubuntu
  5. android画日历
  6. android - anim translate中 fromXDelta
  7. Android(安卓)说说EditText里面的属性
  8. android获取NetworkMode
  9. How to set Android camera orientation
  10. Android跳转浏览器打开URL