1. 程式人生 > >Android百度地圖(三):百度地圖畫運動軌跡及圖層點選事件處理

Android百度地圖(三):百度地圖畫運動軌跡及圖層點選事件處理

上篇文章講述瞭如何在地圖顯示位置點,這篇文章主要講述如何在地圖上畫運動軌跡,以及地圖圖層點選事件的處理。

很多運動類的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


彈出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訊號不好,精度不高,所以在開闊地帶,運動軌跡效果更好。

相關推薦

Android地圖():圖畫運動軌跡事件處理

上篇文章講述瞭如何在地圖顯示位置點,這篇文章主要講述如何在地圖上畫運動軌跡,以及地圖圖層點選事件的處理。 很多運動類的app都有畫出跑步者運動軌跡的需求,拿咕咚來說,我們看一下它的效果圖: 咕咚運動軌跡圖 本篇將要實現的效果 1.跑步結束後,靜態的畫出整個運動

讀取本地座標檔案,在圖畫運動軌跡(2018新華“物聯網終端行為分析”第題)

目錄 問題描述 解決思路 1.註冊百度金鑰 2.建立本地TXT檔案。 3.編寫HTML程式碼 4.搭建本地HTML伺服器 5.在百度地圖顯示運動軌跡 參考文獻 問題描述 該部分內容來自新華三NAVIGATE創客節-黑客鬆“物聯網終端行為分析”第三題:已知一

js仿地圖拖拽、縮放、添加功能(原創)

ets tle clas 火狐 相對 inner tlist posit css 最近項目中完成的需求,仿百度地圖中的功能: 要求:1.底層圖可以拖拽、縮放。    2.拖拽一個圖標,在底層圖上對應位置添加一個標註點,該標註點位置要隨底層圖移動。    3.添加的標註

地圖API入門——(7)新增或刪除

一個地圖,可能有很多圖層。以交通層為例,如下: var map = new BMap.Map("container"); var point = new BMap.Point(123.123, 12,

可能是最詳細的Android事件處理詳解()

前兩篇文章: 可能是最詳細的Android點選事件處理詳解 可能是最詳細的Android點選事件處理詳解(二) 這裡再次延伸一下,在ScrollView和RecyclerView巢狀中touch事件的傳遞過程,以及巢狀滑動衝突的問題。 如上圖,外層是一個Neste

可能是最詳細的Android事件處理詳解(二)

上一篇我們主要詳細描述了touch事件在各層的傳遞 本篇文章主要是對比touch在不可滾動和可滾動的ViewGroup事件的傳遞過程 如上圖: - 左圖:是ViewGroup巢狀View,不可滑動 - 右圖:也是ViewGroup(RecyclerView)巢

可能是最詳細的Android事件處理詳解

面試的時候,很多時候都會問到Touch事件的傳遞,而且問法角度都有所不同,但是還是會遵循基本的事件傳遞規則的,可能他問的你沒處理過,但是根據基本規則慢慢思考來回答,都不會錯。 一,簡介 首先我們知道touch事件 主要是是在三個方法中傳遞和處理的。分別是:

Android完美處理RecyclerView實現item條目事件處理

前言: RecyclerView並沒有像ListView那樣提供了OnItemClick,OnItemLongClick等事件回撥介面,所以,我們需要自己寫介面去進行實現。 正題 ①、建立介面類OnRecyclerViewClickListener /** * Recy

Android recyclerView items的側滑刪除以及事件處理

最近專案中需要實現銀行卡側滑刪除以及選擇預設無法刪除的效果,需求效果圖如下: 其實就是一個自定義的列表實現,這裡我用的是recyclerView首先需要自定義DeleteBankRecyclerView繼承RecyclerView,需要注意的是item的點選和

android graphics畫圖的事件處理

這個示例可能在專案中不會遇到,我也不知道用來做什麼,但還是寫出來了,希望給大家一些提示。 package com.jacp.test; import android.app.Activity; import android.content.Context; import

Android中父View和子view的事件處理問題探討

在處理二級選單和下拉欄頂部的幾個按鈕衝突的時候參考了一下魅族的手機處理方法:當二級選單顯示的時候除了點選二級選單的地方可以響應外,點選其他區域會先收回二級選單然後才能做其他的操作。為了實現這一方式我的思路是:1、首先判斷當前二級選單是否處於顯示的轉態2、根據二級選單的顯示與否

Android XRecyclerView最簡單的item事件處理

以前一直都是用PullToRefresh,後來覺得還是太out了。現在很多人都是用RecyclerView,很簡單的用法,佈局多樣化,主要是有瀑布流。這才知道RecyclerView.LayoutManager真正的強大。 但是說要addHeaderView這

Android自定義佈局系列之一:流式佈局(含TextView的事件

前言:   之前寫了Unity優化方面的文章,之後就沒寫了。之後想把C盤擴大點,室友試了分割槽助手,很好用,也成功了,我心動也試了下,以為不會出什麼意外,更不會出現資料丟失,抱著僥倖的心理沒臨時備份,哎!沒想到最重要的E盤(所有資料)裡所有資料都丟失了,之後用了資料恢復,

[Android]View.post(),android7.0(sdk24以上)不執行的問題(部分Click事件無效的原因)

我們熟知View.post()和Handler.post(),雖然最後執行過程還會走到Handler的post()方法中,但是View.post()做了許多額外的工作,所以我認為如非迫不得己,建議直接

android開啟外部地圖導航(、高德、騰訊)

1.參考下面的地址:我的呼叫百度的就是採用這個文章的方法 https://blog.csdn.net/hyyz3293/article/details/76836633 2,我自己採用的方法,如下; //todo:獲取當前自己的位置; getLocation(new BDLocatio

android 地圖系列之新增覆蓋物和覆蓋物的事件

之前講了百度地圖定位和地圖基本操作,這篇部落格講一下,怎麼去給地圖新增覆蓋物,並當點選覆蓋物的時候顯示詳細資訊。 要給地圖新增覆蓋物,首先需要覆蓋物的經緯度,如果還要實現點選事件,顯示詳細的資訊,還需要覆蓋物的描述資訊(如圖片,位置名稱等),所以先新建一個實體

Android地圖(六):地圖POI檢索,行政區邊界、公交、線路規劃查詢,地理編碼介紹

上一篇文章介紹了百度鷹眼sdk監控進出圍欄的功能,本篇將詳細介紹百度地圖中POI檢索、公交查詢、行政區邊界座標獲取、兩點之間的路徑規劃和地理編碼(座標和地址之間的轉換)。 一 POI檢索 1.POI簡介 POI是興趣點的意思,地圖上標註的商鋪、飯店、學校、銀行、醫院、車站等等都是POI。 地圖上的POI是可

地圖地圖指定省市進行描邊處理,省市外進行半透明遮蓋。

//指定省市進行描邊處理,省市外進行半透明遮蓋。 function getBoundary2(map,city){ var bdary = new BMap.Boundary(); bdary.get(city, function(rs){//獲取行政區域

地圖下載|地圖

如今人們的生活水平在飛速提高,現在無論是有車的還是沒車的,出行一定少不了手機地圖導航,特別是旅行遊玩的,到了一個陌生城市,出行沒有導航是非常不方便的。目前我們國內最大的兩個地圖導航APP就是百度地圖和高德地圖了吧。百度地圖下載連結應用簡介百度地圖是可以為使用者提供智慧路線規劃、智慧導航、實時路況等出行的手機地

地圖全景——經緯度顯示全景

百度地圖全景的顯示 我是用的是百度全景SDK2.6.2的版本,之前的版本android8不相容,在是用這最新的版本中,會碰到一些閃退問題 在這邊我就直接上程式碼!!!本人話少! 在AndroidManifest.xml檔案中,加入許可權 <supports-screens