功能描述:實(shí)現(xiàn)一個普通的地圖展示党觅,地圖上有當(dāng)前定位小藍(lán)點(diǎn)和門店定位Marker信息术荤。當(dāng)前定位需要從定位服務(wù)異步獲取倚喂,可能失敗,門店的位置從接口異步獲取,兩個異步的數(shù)據(jù)最終展示在一個地圖View上端圈,并且Marker需要展示info window焦读,需要兩者不重疊不遮擋完全展示。
效果如下圖:
接入準(zhǔn)備:
1舱权、下載jar包(如Android_Map3D_SDK_V5.2.1_20170630.jar)矗晃,放入工程libs目錄。
2宴倍、build.gradle文件添加:
compile 'com.amap.api:3dmap:latest.integration'
3张症、添加meta-date,appkey信息鸵贬。
4俗他、添加地圖需要的權(quán)限,如定位等阔逼。
使用步驟:
xml中添加布局:
<com.amap.api.maps.MapView
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_marginTop="30dp" />
SDK底層使用OpenGL ES實(shí)現(xiàn)了兩個地圖組件兆衅,分別是GLSurfaceView、TextureView嗜浮。
特點(diǎn):
1羡亩、GLSurfaceView
包括 MapView、MapFragment危融、SupportMapFragment 三種容器畏铆。下面簡單介紹一下 SupportMapFragment:
MapFragment 是 Android Fragment 類的一個子類,用于在 Android Fragment 中放置地圖吉殃。 MapFragment 也是地圖容器辞居,與 MapView 一樣提供對 AMap 對象(地圖的控制類)的訪問權(quán)。與 MapView 相比 SupportMapFragment 方便之處在于其可以更好的管理地圖的生命周期寨腔,布局靈活速侈。
2、TextureView
包括TextureMapView迫卢、TextureMapFragment、TextureSupportMapFragment 三種容器冶共。
使用場景:您將MapView與其他的GLSurfaceView(比如相機(jī))疊加展示乾蛤,或者是在ScrollView中加載地圖時,建議使用TextureMapView及SupportTextureMapFragment來展示地圖捅僵,可以有效解決 GLSurfaceView 疊加時出現(xiàn)的穿透家卖、滾動黑屏等問題。
根據(jù)需求合理選擇實(shí)現(xiàn)的組件和方式
初始化MapView和管理對象AMap庙楚,顯示地圖
MapView mMapView.onCreate(savedInstanceState);
aMap = mMapView.getMap();
// info window的適配器
aMap.setInfoWindowAdapter(new AMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
return null;
}
}
// 搞一些marker上荡,然后給marker設(shè)置info window,這個過程由aMap來完成
Marker maker = aMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.fromBitmap(
BitmapFactory.decodeResource(getResources(), R.drawable.xxx)))
.title("title")
.snippet("xxx")
.anchor(0.5F, 0.5F)
.position(storeLatLng)
.draggable(false)
.setFlat(true));
// 設(shè)置地圖的UI屬性
UiSettings uiSettings = aMap.getUiSettings();
// 隱藏縮放控件
uiSettings.setZoomControlsEnabled(false);
// 隱藏比例尺控件
uiSettings.setScaleControlsEnabled(false);
...
// 設(shè)置事件交互
aMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
// 消耗事件,不繼續(xù)傳遞
return true;
}
});
aMap.setOnInfoWindowClickListener(new AMap.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
// 點(diǎn)擊打開導(dǎo)航dialog
ToastUtil.showShortMsg(XXX.this, "打開導(dǎo)航dialog");
}
});
// 開始定位酪捡,并顯示定位小藍(lán)點(diǎn)
final MyLocationStyle myLocationStyle = new MyLocationStyle();
// 設(shè)置自定義小藍(lán)點(diǎn)的圖標(biāo)
myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.mylocation));
// 設(shè)置小藍(lán)點(diǎn)的錨點(diǎn)
myLocationStyle.anchor(0.5F, 0.5F);
// 設(shè)置小藍(lán)點(diǎn)的邊框顏色
myLocationStyle.strokeColor(getResources().getColor(R.color.blue));
// 設(shè)置小藍(lán)點(diǎn)的填充顏色
myLocationStyle.radiusFillColor(Color.argb(100, 29, 161, 242));
// 設(shè)置小藍(lán)點(diǎn)的邊框粗細(xì)
myLocationStyle.strokeWidth(1.0F);
// 表示地圖只定位一次
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);
// 是否顯示定位小藍(lán)點(diǎn)
myLocationStyle.showMyLocation(true);
aMap.setMyLocationStyle(myLocationStyle);
// 高德api在5.0對定位的實(shí)現(xiàn)做了更改叁征,官網(wǎng)(https://lbs.amap.com/api/android-sdk/guide/create-map/mylocation)
aMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {
@Override
public void onMyLocationChange(Location location) {
// 從location對象中獲取經(jīng)緯度信息,地址描述信息逛薇,建議拿到位置之后調(diào)用逆地理編碼接口獲绒嗵邸(獲取地址描述數(shù)據(jù)章節(jié)有介紹)
if (location != null) {
locationLatLng = new LatLng(location.getLatitude(), location.getLongitude());
if (storeLatLng != null) {
zoomToSpanWithCenter();
}
}
}
});
// 設(shè)置為true表示啟動顯示定位小藍(lán)點(diǎn),false表示隱藏定位小藍(lán)點(diǎn)并不進(jìn)行定位永罚,默認(rèn)是false啤呼。
aMap.setMyLocationEnabled(true);
現(xiàn)在地圖就可以正常展示了,定位完成后呢袱,會顯示定位小藍(lán)點(diǎn)官扣,我們設(shè)置為只定位一次,這樣可以節(jié)省性能和電量羞福,并且也符合需求醇锚。
還有一些問題:
1、高德地圖縮放級別分為大概20級坯临,我們需要顯示一個合適的級別焊唬。
2、我們給marker設(shè)置的info window會出現(xiàn)被遮擋的情況看靠。
接下來對地圖做進(jìn)一步的約束
1赶促、縮放到合適的級別:
LatLngBounds.Builder這個api可以幫助我們獲取最佳的展示縮放比例,我們需要指定一個中心點(diǎn)挟炬,另外在傳入一些我們需要展示的經(jīng)緯度的集合鸥滨,然后它會返給我們一個存儲有合適范圍約束的LatLngBounds對象。
private LatLngBounds getLatLngBounds(LatLng centerPoint, List<LatLng> pointList) {
LatLngBounds.Builder builder = LatLngBounds.builder();
if (centerPoint != null) {
for (int i = 0; i < pointList.size(); i++) {
LatLng p = pointList.get(i);
LatLng p1 = new LatLng((centerPoint.latitude * 2) - p.latitude,
(centerPoint.longitude * 2) - p.longitude);
builder.include(p);
builder.include(p1);
}
}
return builder.build();
}
有了合適范圍約束對象后谤祖,我們的marker和當(dāng)前位置小藍(lán)點(diǎn)都可以展示在地圖里婿滓,需要我們調(diào)整一下地圖的顯示
LatLngBounds bounds = getLatLngBounds(centerLatLng, pointList);
// 第二個參數(shù)為地圖設(shè)置padding
aMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
設(shè)置好padding,防止顯示的marker等離地圖范圍邊挨得太近粥喜。
2凸主、info window被遮擋,顯示不全的問題
在一番搜索之后额湘,發(fā)現(xiàn)并沒有合適的api可以使用卿吐,┭┮﹏┭┮
突然想到是不是可以添加一些不顯示的點(diǎn)來重新讓地圖定位,用這些不可見的點(diǎn)來把我們要顯示的內(nèi)容給圈起來锋华,圈定一個范圍嗡官。
相對于定位的小藍(lán)點(diǎn),門店的點(diǎn)有四個相對的位置毯焕,如下圖:
其中衍腥,圖2和圖3容易被遮擋,我們在這兩個位置的上方和右方添加兩個點(diǎn)就可以顯示我們的需求
public void zoomToSpanWithCenter() {
List<LatLng> pointList = new ArrayList<>();
LatLng centerLatLng;
LatLng helperLatLngVertical = null;
LatLng helperLatLngHorizontal = null;
// 判斷店鋪和當(dāng)前位置哪個緯度更高,然后添加輔助點(diǎn)以更好地分配位置防止店鋪info window顯示不全
if (storeLatLng.latitude > locationLatLng.latitude) {
helperLatLngVertical = new LatLng(Math.max(storeLatLng.latitude, locationLatLng.latitude)
+ Math.abs(storeLatLng.latitude - locationLatLng.latitude), storeLatLng.longitude);
}
// 判斷店鋪和當(dāng)前位置哪個經(jīng)度更靠右側(cè)婆咸,然后添加輔助點(diǎn)以更好地分配位置防止店鋪info window顯示不全
if (storeLatLng.longitude > locationLatLng.longitude) {
helperLatLngHorizontal = new LatLng(storeLatLng.latitude,
Math.max(storeLatLng.longitude, locationLatLng.longitude)
+ Math.abs(storeLatLng.longitude - locationLatLng.longitude) / 10);
}
pointList.add(storeLatLng);
pointList.add(locationLatLng);
if (helperLatLngVertical != null) {
pointList.add(helperLatLngVertical);
}
if (helperLatLngHorizontal != null) {
pointList.add(helperLatLngHorizontal);
}
centerLatLng = new LatLng((locationLatLng.latitude + storeLatLng.latitude
+ (helperLatLngVertical != null ? helperLatLngVertical.latitude : 0)
+ (helperLatLngHorizontal != null ? helperLatLngHorizontal.latitude:0)) / pointList.size(),
(locationLatLng.longitude + storeLatLng.longitude
+ (helperLatLngVertical != null ? helperLatLngVertical.longitude : 0)
+ (helperLatLngHorizontal != null ? helperLatLngHorizontal.longitude:0)) / pointList.size());
LatLngBounds bounds = getLatLngBounds(centerLatLng, pointList);
// 第二個參數(shù)為地圖設(shè)置padding
aMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
}
最終顯示不會被遮擋竹捉,并且縮放顯示也合乎要求,O(∩_∩)O
掃尾工作:
1擅耽、檢查有沒有泄露情況活孩、該釋放的資源有沒有及時釋放
@Override
protected void onDestroy() {
super.onDestroy();
mMapViewStoreDetail.onDestroy();
if (mLocationClient != null) {
mLocationClient.onDestroy();
}
}
在Android Studio里打開Android Profiler查看打開、關(guān)閉activity情況下實(shí)例有沒有及時回收釋放乖仇。
2憾儒、有沒有