Android百度地图(三):百度地图画运动轨迹及图层点击事件处理
2017-09-16 14:40
435 查看
上篇文章讲述了如何在地图显示位置点,这篇文章主要讲述如何在地图上画运动轨迹,以及地图图层点击事件的处理。
很多运动类的app都有画出跑步者运动轨迹的需求,拿咕咚来说,我们看一下它的效果图:
咕咚运动轨迹图
本篇将要实现的效果
1.跑步结束后,静态的画出整个运动轨迹
2.跑步过程中,时时动态的画运动轨迹
效果图
如何实现:
1.将点与点连成线,在百度地图MapView上画出线条图层;
2.获取定位点List<LatLng>:通过百度定位sdk:LocationClient类获取,户外运动画运动轨迹,要求位置点的精度高,所以我们必须使用gps定位类型的位置结果。
更多百度定位sdk参数详解请阅读篇头百度地图(一)文章
运动轨迹效果
轨迹图
2.添加起始图标图层、点击图层响应事件
运动轨迹效果,点击图标弹出信息窗口
点击起始图标
点击图标弹出信息窗口弹出Toast
弹出Toast
到这里,运动结束后画出整个轨迹图和图层添加点击事件就介绍完了。
运动轨迹:箭头为当前位置和方向
关键在于取点:gps刚接收到信号时返回的一些点精度不高,容易造成位置偏移,如何取点很重要。
退出记得释放资源
注:我们画运动轨迹要求定位sdk返回的位置精度很高,轨迹的效果才会好,因而必须接受gps位置点。但是gps位置的在刚开始收到信号时精度不高,会出现位置漂移的情况,所以要选取一个精度较好的点。在建筑物、桥梁、大树、隧道里面,gps信号不好,精度不高,所以在开阔地带,运动轨迹效果更好。
当运动轨迹效果不佳时,可以利用百度鹰眼sdk采集位置数据,然后查询纠偏后轨迹,这样效果会好很多,详情请阅读:
Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼sdk服务
更多百度地图、定位sdk参数详解请阅读篇头百度地图(一、二)文章
如果各位看官觉得文章不错,别忘了点个喜欢。
源码下载地址 https://github.com/zhuhaoHappig/BaiduMapApi
作者:zhh_happig
链接:http://www.jianshu.com/p/2ad4c2077dfd
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
很多运动类的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 - 点击监听者 另外,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; } });
运动轨迹效果,点击图标弹出信息窗口
点击起始图标
点击图标弹出信息窗口弹出Toast
弹出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; } //注意:这里只要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参数详解请阅读篇头百度地图(一、二)文章
如果各位看官觉得文章不错,别忘了点个喜欢。
源码下载地址 https://github.com/zhuhaoHappig/BaiduMapApi
作者:zhh_happig
链接:http://www.jianshu.com/p/2ad4c2077dfd
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章推荐
- Android百度地图(三):百度地图画运动轨迹及图层点击事件处理
- Android百度地图画运动轨迹及图层点击事件处理
- android--面试题:多次点击事件处理
- android之实现各个组件点击事件处理
- Android:ListView中嵌入GridView,处理点击事件的冲突
- Android-11-点击事件的4种处理方式
- android 百度地图定位与覆盖物的添加,以及他们的点击事件
- android dialog在activity中,如何处理activity捕捉不到back点击事件
- android 点击、滑动事件的处理 GestureDetector
- Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼
- Android滑屏与子控件点击事件处理
- android之实现各个组件点击事件处理
- 百度地图定位图层,以及覆盖物点击事件
- Android点击推送时处理onResume事件extras为null
- android Switch控件一直处于聚焦状态,将屏蔽Preference的点击事件(处理方式)_xp
- Android开发之带CheckBox的ListView的点击事件的处理
- Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼
- Android自定义TextView中的超链接点击事件处理
- Android笔记2—处理点击事件的几种方法
- AndroidTV/机顶盒 ListView获取焦点与点击事件问题处理方案