高德地圖路線導航製作
轉載請註明出處:https://blog.csdn.net/Dreamer_man/article/details/104193832
由於公司項目需求,特地去官網,重新溫習了一遍高德的地圖製作。並且自己寫了個Demo,主要包含5大功能:地圖、定位、自定義marker、路線制定、模擬導航。下面是效果圖(代碼下載鏈接在最下面,有需要的拿走):
1. 準備工作:
首先需要做一些地圖的準備工作,這就好比寫代碼前,要洗手通風一樣。
1.1 獲取Key
第一步,去高德官網申請key,具體申請方式,獲取key已經講的很清楚了,這裏我就不細細道來了。
圖1-1 申請Key
1.2 添加SDK
第二步,添加SDK。這裏有兩種添加方式,第一種是通過拷貝添加SDK,第二種是通過Gradle集成SDK。這裏我選擇的是第二種,當然也建議大家用第二種,爲什麼呢?因爲懶,哈哈,當然具體需要集成什麼SDK,根據大家業務需求寫。如果小夥伴們對第一種也感興趣,可以參考添加SDK。
//3D地圖so及jar和導航
implementation 'com.amap.api:navi-3dmap:latest.integration'
//定位功能
implementation 'com.amap.api:location:latest.integration'
//搜索功能
implementation 'com.amap.api:search:latest.integration'
注意(此乃官方吐槽):
1. navi導航SDK 5.0.0以後版本包含了3D地圖SDK,所以請不要同時引入 map3d 和 navi SDK。
2. 依照上述方法引入 SDK 以後,不需要在libs文件夾下導入對應SDK的 so 和 jar 包,會有衝突。
第2點說人話就是,如果在gradle中添加了上面幾個依賴後,就不需要添加其他地圖so庫和jar包(手動滑稽,是不是很方便)
1.3 配置AndroidManifest.xml
第三步,配置AndroidManifest.xml
首先,聲明權限
<!--地圖包、搜索包需要的基礎權限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允許程序設置內置sd卡的寫權限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允許程序獲取網絡狀態-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允許程序訪問WiFi網絡信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允許程序讀寫手機狀態和身份-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允許程序訪問CellID或WiFi熱點來獲取粗略的位置-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用於訪問GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--這個權限用於獲取wifi的獲取權限,wifi信息會用來進行網絡定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--這個權限用於允許程序在手機屏幕關閉後後臺進程仍然運行-->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
然後,設置高德key
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="開發者申請的key"/>
最後,添加定位服務(這點很重要,沒有這個服務,應用無法定位)
<service android:name="com.amap.api.location.APSService"></service>
完事具備,只欠東風,咱們就開始壘代碼。
2. 地圖顯示
第一步,在XML文件中定義MapView控件
<com.amap.api.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
第二步,再初始化地圖,
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (aMap == null) {
aMap = mapView.getMap();
}
注意:
1. mapView.onCreate(savedInstanceState)一定要加上,否則地圖無法顯示。
2. 在activity生命週期中,對mapView進行相應的處理,demo中有體現。
3. 實時定位
第一步,初始化定位參數,設置定位監聽(代碼中都有詳細的註釋)
MyLocationStyle myLocationStyle = new MyLocationStyle();
//設置連續定位模式下的定位間隔,只在連續定位模式下生效,單次定位模式下不會生效。單位爲毫秒。
myLocationStyle.interval(2000);
//定位藍點展現模式,默認是LOCATION_TYPE_LOCATION_ROTATE
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);
//設置是否顯示定位小藍點,用於滿足只想使用定位,不想使用定位小藍點的場景,設置false以後圖面上不再有定位藍點的概念,但是會持續回調位置信息。
myLocationStyle.showMyLocation(true);
//設置定位藍點的Style
aMap.setMyLocationStyle(myLocationStyle);
// 設置定位監聽
aMap.setLocationSource(this);
//設置爲true表示啓動顯示定位藍點,false表示隱藏定位藍點並不進行定位,默認是false。
aMap.setMyLocationEnabled(true);
// 設置地圖模式,aMap是地圖控制器對象。1.MAP_TYPE_NAVI:導航地圖 2.MAP_TYPE_NIGHT:夜景地圖 3.MAP_TYPE_NORMAL:白晝地圖(即普通地圖) 4.MAP_TYPE_SATELLITE:衛星圖
aMap.setMapType(AMap.MAP_TYPE_NORMAL);
//設置默認定位按鈕是否顯示,非必需設置。
aMap.getUiSettings().setMyLocationButtonEnabled(true);
//控制比例尺控件是否顯示,非必須設置。
aMap.getUiSettings().setScaleControlsEnabled(true);
第二步,實現AMap.setLocationSource監聽器,並且回調activate()和deactivate()兩個方法。activate()方法是在激活定位的時候觸發,需要在裏面初始化定位參數,並開始定位。deactivate()方法是在定位停止的時候觸發,需要在方法裏停止定位,避免不必要的資源浪費。
/**
* 激活定位
*/
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
if (aMapLocationClient == null) {
//初始化定位
aMapLocationClient = new AMapLocationClient(this);
//初始化定位參數
aMapLocationClientOption = new AMapLocationClientOption();
//設置定位回調監聽
aMapLocationClient.setLocationListener(this);
//設置爲高精度定位模式
aMapLocationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//設置定位參數
aMapLocationClient.setLocationOption(aMapLocationClientOption);
//啓動定位
aMapLocationClient.startLocation();
}
}
/**
* 停止定位
*/
@Override
public void deactivate() {
mListener = null;
if (aMapLocationClient != null) {
aMapLocationClient.stopLocation();
aMapLocationClient.onDestroy();
}
aMapLocationClient = null;
}
第三步,在定位回調中設置顯示定位小藍點,isFirstLocationn的作用是防止拖動地圖後,定位小藍點老是返回到屏幕的中心位置。
public void onLocationChanged(AMapLocation aMapLocation) {
if (mListener != null && aMapLocation != null) {
this.aMapLocation = aMapLocation;
if (aMapLocation.getErrorCode() == 0) {
if (isFirstLocation) {
aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude())));
mListener.onLocationChanged(aMapLocation);// 顯示系統小藍點
isFirstLocation = false;
}
} else {
Log.e("TAG", "定位失敗!!!");
}
}
}
注意:
1. setMyLocationEnabled(true)方法必須在setLocationSource(this)定位監聽之後執行,否則定位會失效。
2. AMap.getUiSettings()是獲得高德地圖控件對象,可以通過這個方法設置地圖控件
4. 自定義marker
第一步,在XML文件中定義marker佈局(僅爲demo,具體樣式根據個人需求定製)
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="路線製作"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開始導航"/>
第二步,實現AMap.setInfoWindowAdapter()的監聽,回調 getInfoWindow()和getInfoContent()兩個方法,具體這兩個方法有什麼區別,繪製自定義marker已經講的很詳細了,我就不細說了,主要區別在於getInfoContent()不能修改整個 InfoWindow 的背景和邊框,無論自定義的樣式是什麼樣,SDK 都會在最外層添加一個默認的邊框。 在這裏我實現了getInfoWindow()方法。
public View getInfoWindow(Marker marker) {
if (infoView == null) {
infoView = LayoutInflater.from(this).inflate(R.layout.marker_info_window, null);
}
render(marker, infoView);
return infoView;
}
private void render(final Marker marker, View infoView) {
infoView.findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
infoView.findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
5.路線制定
第一步,初始化RouteSearch對象,並且設置查詢結果的回調監聽器
routeSearch = new RouteSearch(this);
routeSearch.setRouteSearchListener(this);
第二步,需要確定起點和終點,畢竟兩點確定一條線。
startLatLonPoint = new LatLonPoint(aMapLocation.getLatitude(), aMapLocation.getLongitude());
endLatLonPoint = new LatLonPoint(marker.getPosition().latitude, marker.getPosition().longitude);
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(startLatLonPoint, endLatLonPoint);
第三步,選擇路線,有駕車線路、步行線路、公交線路、騎行線路、貨車線路。爲了方便展示,我這裏實現了步行線路,具體什麼線路,根據個人需求進行選擇。
RouteSearch.WalkRouteQuery query = new RouteSearch.WalkRouteQuery(fromAndTo, RouteSearch.WALK_DEFAULT);
第四步,計算路線,至於如何計算,大家大可不用關心,這些計算方法高德已經封裝好接口了,咱們拿來直接用就好。
routeSearch.calculateWalkRouteAsyn(query);
第五步,根據計算結果,畫出路線
public void onWalkRouteSearched(WalkRouteResult walkRouteResult, int i) {
aMap.clear();
if (i == AMapException.CODE_AMAP_SUCCESS) {
if (walkRouteResult != null && walkRouteResult.getPaths() != null) {
if (walkRouteResult.getPaths().size() > 0) {
routeResult = walkRouteResult;
final WalkPath walkPath = walkRouteResult.getPaths().get(0);
if (walkPath == null) {
return;
}
WalkRouteOverlay overlay = new WalkRouteOverlay(
this, aMap, walkPath,
walkRouteResult.getStartPos(),
walkRouteResult.getTargetPos());
overlay.removeFromMap();
overlay.addToMap();
overlay.zoomToSpan();
}
}
}
}
注意:
1. 地圖SDK V4.1.3版本開始,SDK不再提供 com.amap.api.maps.overlay 包下的 overlay,已在官方demo中開源。如果只有行走路線的話,需要下面這幾個類。
圖5-1行走路線的overlay
6. 模擬導航
在這先解釋一下什麼是模擬導航,模擬導航就是真實模擬實時導航的情況,比如A爲起點,B爲終點,實時導航需要你從A點走到B點,而模擬導航不需要你移動,它可以模擬移動,自動從A點走到B點。當然這只是爲了方便展示,真實情景還是需要實時導航的,不過只需要改變AMapNavi.startNavi()方法的參數即可,詳細情節後面會有敘述。
第一步,在XML文件中定義AMapNaviView控件
<com.amap.api.navi.AMapNaviView
android:id="@+id/naviView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.amap.api.navi.AMapNaviView>
第二步,獲取 AMapNaviView實例,並設置監聽。
aMapNaviView = findViewById(R.id.naviView);aMapNaviView.setAMapNaviViewListener(this);aMapNaviView.onCreate(savedInstanceState);
第三步,獲取AMapNavi實例,並設置監聽
//獲取AMapNavi實例
aMapNavi = AMapNavi.getInstance(getApplicationContext());
//添加監聽回調,用於處理算路成功
aMapNavi.addAMapNaviListener(this);
第四步,計算步行規劃路線,AMapNavi對象初始化成功後,會觸發onInitNaviSuccess方法。
public void onInitNaviSuccess() {
aMapNavi.calculateWalkRoute(startNaviLatLng, endNaviLatLng);
}
第五步,開始導航,路線規劃成功後,會觸發onCalculateRouteSuccess()方法,在這裏咱們開始導航。
public void onCalculateRouteSuccess(int[] ints) {
aMapNavi.startNavi(NaviType.EMULATOR);
}
注意:
1. NaviView與MapView一樣,要根據Activity的生命週期來進行相應處理,demo中有體現,在這裏提別提醒一下在Activity銷燬的時候調用AMapNavi的stopNavi()和destory()方法,來停止導航,否則再次導航時會出現AMapNavi初始化失敗的問題!
protected void onDestroy() {
super.onDestroy();
mAMapNaviView.onDestroy();
//since 1.6.0 不再在naviview destroy的時候自動執行AMapNavi.stopNavi();請自行執行
mAMapNavi.stopNavi();
mAMapNavi.destroy();
}
2. 如果需要導航語音的話,調用setUseInnerVoice()方法即可實現。
aMapNavi.setUseInnerVoice(true);
到這裏一款導航app的雛形就做好了,如果還想要功能變得更強大,只需添枝加葉即可。
導航appDemo:
https://download.csdn.net/download/Dreamer_man/12138974