目前在做一個產(chǎn)品的大改版,主要是交互方式變化很大,尤其是增加了地圖相關(guān)交互盯捌,類似于滴滴、優(yōu)步首頁蘑秽。
開發(fā)時遇到的很大的一個問題就是縮放控制饺著,由于界面中同時存在地圖及輸入覆蓋層箫攀,在地圖上添加標注時需要精確控制標注顯示區(qū)域,使標注顯示范圍控制在覆蓋層區(qū)域上方幼衰。
查閱android端相關(guān)api后發(fā)現(xiàn)縮放控制主要由此類 MapStatusUpdateFactory
間接來完成靴跛。
嘗試所有方法后發(fā)現(xiàn)百度提供的api不能同時控制地理范圍及中心點??,
MapStatusUpdateFactory.newLatLngBounds(builder.build())
此方法可控制所有標注顯示在以地圖中心為中心點的整個地圖上渡嚣,但無法控制中心點位置梢睛。
嘗試人為構(gòu)造邊界點來控制顯示
如上圖,紅色為原始點识椰,紫色為根據(jù)當前屏幕未被覆蓋區(qū)域?qū)捀呒敖?jīng)緯度差值比例生成的邊界點绝葡,實際測試后發(fā)現(xiàn) MapStatusUpdateFactory.newLatLngBounds(builder.build())
此方法不能完美顯示。
嘗試獲取設(shè)置中心點及縮放比例
MapStatus 此類也可控制地圖腹鹉。
MapStatus mapStatus = new MapStatus.Builder()
.target(builder.build().getCenter())
.zoom(zoom)
.targetScreen(point).build();
mMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(mapStatus));
此方法可控制中心點經(jīng)緯度及中心點屏幕坐標藏畅,適合精確控制單個點。但是MapStatus.Builder 此構(gòu)造類只提供了縮放級別設(shè)置功咒,并不能設(shè)置經(jīng)緯度范圍愉阎,在查閱了api后發(fā)現(xiàn)百度并未提供根據(jù)經(jīng)緯度范圍獲取縮放比例的api,網(wǎng)上給出的很多方法為通過比例尺力奋、縮放級別計算榜旦,很不靠譜...... 遂放棄此方法。
詢問了百度地圖的產(chǎn)品和技術(shù)刊侯,告知的方法還是通過MapStatusUpdateFactory
來完成章办,并不能達到我們的要求锉走,但是ios 提供了相關(guān)的方法 ??滨彻。
為了不影響開發(fā)進度,開發(fā)前期采用了人為構(gòu)造邊界點的方法挪蹭。
在項目主流程接近完成時亭饵,又重新開始地圖的開發(fā),對百度提供的一些類進行了仔細研究梁厉。發(fā)現(xiàn) MapStatusUpdateFactory
類的 MapStatusUpdateFactory
方法辜羊,也就是人為構(gòu)造邊界點所使用的方法:
public static MapStatusUpdate newLatLngBounds(LatLngBounds var0) {
if(var0 == null) {
return null;
} else {
MapStatusUpdate var1 = new MapStatusUpdate(3);
var1.d = var0;
return var1;
}
}
在所構(gòu)造的 MapStatusUpdate
對象在此方法mMap.animateMapStatus(MapStatusUpdateFactory.newLatLngBounds(builder.build()));
調(diào)用過程中,會調(diào)用以下方法:
MapStatusUpdate(int var1) {
this.a = var1;
}
MapStatus a(e var1, MapStatus var2) {
if(null != var1 && null != var2) {
switch(this.a) {
case 1:
return this.b;
case 2:
return new MapStatus(var2.rotate, this.c, var2.overlook, var2.zoom, var2.targetScreen, (LatLngBounds)null);
case 3:
double var3 = 0.0D;
double var5 = 0.0D;
double var7 = 0.0D;
double var9 = 0.0D;
GeoPoint var11 = CoordUtil.ll2mc(this.d.southwest);
GeoPoint var12 = CoordUtil.ll2mc(this.d.northeast);
var3 = var11.getLongitudeE6();
var5 = var12.getLatitudeE6();
var7 = var12.getLongitudeE6();
var9 = var11.getLatitudeE6();
float var13 = var1.a((int)var3, (int)var5, (int)var7, (int)var9, var2.a.j.right - var2.a.j.left, var2.a.j.bottom - var2.a.j.top);
LatLng var14 = this.d.getCenter();
return new MapStatus(var2.rotate, var14, var2.overlook, var13, var2.targetScreen, (LatLngBounds)null);
}
case 3 返回的 MapStatus
對象的構(gòu)造方法為:
MapStatus(float var1, LatLng var2, float var3, float var4, Point var5, LatLngBounds var6) {
this.rotate = var1;
this.target = var2;
this.overlook = var3;
this.zoom = var4;
this.targetScreen = var5;
if(this.target != null) {
this.b = CoordUtil.ll2mc(this.target).getLongitudeE6();
this.c = CoordUtil.ll2mc(this.target).getLatitudeE6();
}
this.bound = var6;
}
注意這個構(gòu)造方法的 var4
參數(shù)词顾,此參數(shù)為縮放級別八秃。
傳入的值便是由此方法計算出來的:
float var13 = var1.a((int)var3, (int)var5, (int)var7, (int)var9, var2.a.j.right - var2.a.j.left, var2.a.j.bottom - var2.a.j.top);
這個類是什么鬼
public class e implements b {
public e(Context var1, String var2) {
this.A = var1;
this.f = new ArrayList();
this.an = var2;
}
}
本想自己實例化一個對象,發(fā)現(xiàn)找不到這個 an
到底是什么東西...... 直接實例化的方法失敗了肉盹。
在經(jīng)過一番查找后昔驱,在 BaiduMap
中找到了這個類的實例
private e i;
BaiduMap(af var1) {
this.j = var1;
this.i = this.j.b();
this.d = ad.b;
this.c();
}
BaiduMap(j var1) {
this.h = var1;
this.i = this.h.a();
this.d = ad.a;
this.c();
}
并且是在 BaiduMap
實例化時就被實例化了!I先獭骤肛!
這個屬性是 private
的纳本,并不能直接獲取,需要通過反射獲取:
Field eField = null;
eField = BaiduMap.class.getDeclaredField("i");
eField.setAccessible(true);
com.baidu.platform.comapi.map.e zoomUtils = (com.baidu.platform.comapi.map.e) eField.get(baiduMap);
獲取到這個類的實例后腋颠,就可以調(diào)用它的方法計算縮放級別了:
public float a(int var1, int var2, int var3, int var4, int var5, int var6) {
if(!this.i) {
return 12.0F;
} else if(this.g == null) {
return 0.0F;
} else {
Bundle var7 = new Bundle();
var7.putInt("left", var1);
var7.putInt("right", var3);
var7.putInt("bottom", var4);
var7.putInt("top", var2);
var7.putInt("hasHW", 1);
var7.putInt("width", var5);
var7.putInt("height", var6);
return this.g.c(var7);
}
}
傳入相關(guān)參數(shù)
GeoPoint southwest = CoordUtil.ll2mc(builder.build().southwest);
GeoPoint northeast = CoordUtil.ll2mc(builder.build().northeast);
double left = southwest.getLongitudeE6();
double top = northeast.getLatitudeE6();
double right = northeast.getLongitudeE6();
double bottom = southwest.getLatitudeE6();
float zoom = zoomUtils.a((int) left, (int) top, (int) right, (int) bottom, width, height);
此時就得到縮放級別了繁成,最后的 width
、height
為顯示區(qū)域 淑玫。
上述計算方法經(jīng)過層層調(diào)用巾腕,最終會調(diào)用native方法
public class JNIBaseMap {
public long a;
public JNIBaseMap() {
}
public native float GetZoomToBound(long var1, Bundle var3);
}
實際測試中,比人為構(gòu)造邊界點的效果好很多絮蒿,但是存在寬高區(qū)域控制無效的情況祠墅,目前暫無更好的辦法,只能期望百度開放相關(guān)的接口了......
最后附上完整代碼
public static float getFitZoom(BaiduMap baiduMap, LatLngBounds.Builder builder, int width, int height) throws Exception {
Field eField = null;
eField = BaiduMap.class.getDeclaredField("i");
eField.setAccessible(true);
com.baidu.platform.comapi.map.e zoomUtils = (com.baidu.platform.comapi.map.e) eField.get(baiduMap);
GeoPoint southwest = CoordUtil.ll2mc(builder.build().southwest);
GeoPoint northeast = CoordUtil.ll2mc(builder.build().northeast);
double left = southwest.getLongitudeE6();
double top = northeast.getLatitudeE6();
double right = northeast.getLongitudeE6();
double bottom = southwest.getLatitudeE6();
float zoom = zoomUtils.a((int) left, (int) top, (int) right, (int) bottom, width, height);
Log.e("zoom",zoom+"");
return zoom;
}
注:百度地圖版本4.5.2