遇到一個需求,在地圖中標識多個地點(全國範圍),地點的gps放到一個xml檔案中,以便隨時修改。要求是地圖要儘可能詳細,但是得把所有地點包括在內。
做法如下:
1、先得到資料的最大和最小經緯度,計算出資料的中心點(也是經緯度);
2、把地圖的zoom level預設一個比較大的值,如19或20之類的。這樣的話肯定是有很多地點是沒有顯示在mapView上的,然後再逐漸減少level的值,以顯示所有的地點。
過程很清晰,看起來沒什麼問題,得出主要代碼如下:
Java代碼
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
comList = this.getComList();//擷取網路攝影機資料
mapView = (MapView) findViewById(R.id.MapView01);
mapView.setStreetView(true);
mapView.setEnabled(true);
mapView.setClickable(true);
mapView.setBuiltInZoomControls(true); // 設定地圖支援縮放
System.out.println("長和寬:"+mapView.getHeight()+","+mapView.getWidth());
mapController = (MapController)mapView.getController();
// locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 位置管理器
// 設定地圖中心點
Double lat1 = (min_y + max_y) / 2 * 1E6;
Double lng1 = (min_x + max_x) / 2 * 1E6;
System.out.println("中心點:"+lat1+","+lng1);
GeoPoint geoPoint = new GeoPoint(lat1.intValue(), lng1.intValue());
mapController.setCenter(geoPoint);
mapController.setZoom(16);
...
Drawable defaultMarker = getResources().getDrawable(R.drawable.arrow);
Drawable activeMarker = getResources().getDrawable(R.drawable.icon);
defaultMarker.setBounds(0, 0, defaultMarker.getMinimumWidth(),
defaultMarker.getMinimumHeight());
PositionsOverlay posOverlay = new PositionsOverlay(defaultMarker,
comList, activeMarker,this);
List<Overlay> overlays = getMapView().getOverlays();
overlays.add(posOverlay);
//根據左上方來判斷
Projection proj = mapView.getProjection();
MapController mapController = mapView.getController();
GeoPoint geoFromPix = proj.fromPixels(0, 0);//
double pix_lng = geoFromPix.getLongitudeE6() / 1E6;// 左上方螢幕像素轉換成的gps經度
double pix_lat = geoFromPix.getLatitudeE6() / 1E6;// 左上方螢幕像素轉換成的gps緯度
// System.out.println("縮放前中心點: "+mapView.getMapCenter());
while (min_x < pix_lng) {// 資料中最小經度如果小於螢幕所對應的最小經度(出界),則縮小地圖,讓資料顯示到螢幕中
System.out.println("縮小地圖1:" + min_x + "," + pix_lng);
mapController.setZoom(mapView.getZoomLevel() - 1);
pix_lng = mapView.getProjection().fromPixels(0, 0)
.getLongitudeE6() / 1E6;
pix_lat = mapView.getProjection().fromPixels(0, 0)
.getLatitudeE6() / 1E6;
}
while (max_y > pix_lat) {// 資料中最大緯度如果大於螢幕所對應的最小緯度(出界),則縮小地圖,讓資料顯示到螢幕中
System.out.println("縮小地圖2");
mapController.setZoom(mapView.getZoomLevel() - 1);
pix_lat = mapView.getProjection().fromPixels(0, 0)
.getLatitudeE6() / 1E6;
}
運行結果,後台狂刷:
Java代碼
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
08-18 07:47:00.076: INFO/System.out(437): 縮小地圖1:121.1004,121.145444
將左上方換成右下角,發現取不到mapView的寬和高。。。
上網找了下,說法如下:
Java代碼
A common mistake made by new Android developers is to use
the width and height of a view inside its constructor. When
a view’s constructor is called, Android doesn’t know yet how
big the view will be, so the sizes are set to zero. The real sizes
are calculated during the layout stage, which occurs after
construction but before anything is drawn. You can use the
onSizeChanged( )method to be notified of the values when they
are known, or you can use the getWidth( ) and getHeight( )methods
later, such as in the onDraw( ) method
http://www.coderanch.com/t/435390/Android/Mobile/screen-size-at-run-time
要等開始布局時才能得到寬和高等特性?這麼說的話使用
Java代碼
pix_lng = mapView.getProjection().fromPixels(0, 0)
.getLongitudeE6() / 1E6;
也是沒意義的了。。。
這樣的話只能等mapView渲染完畢才能處理了.
本來想使用mapView的draw方法來處理,但是無從下手(繼承mapView類來重寫draw方法?),只好寫了個線程,監聽mapView是否完成(完成的話height和width都不會等0了),然後把剛才那段代碼放到線程裡,成功了。。。
新線程代碼:
Java代碼
public void run() {
while (mapView.getHeight() == 0) {
System.out.println("mapView等於0,mapView還沒渲染完畢");
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (mapView.getHeight() != 0) {
/*
* 使用setZoom來讓資料標籤自適應螢幕
*/
//根據左上方來判斷
Projection proj = mapView.getProjection();
MapController mapController = mapView.getController();
GeoPoint geoFromPix = proj.fromPixels(0, 0);//
double pix_lng = geoFromPix.getLongitudeE6() / 1E6;// 左上方螢幕像素轉換成的gps經度
double pix_lat = geoFromPix.getLatitudeE6() / 1E6;// 左上方螢幕像素轉換成的gps緯度
// System.out.println("縮放前中心點: "+mapView.getMapCenter());
while (min_x < pix_lng) {// 資料中最小經度如果小於螢幕所對應的最小經度(出界),則縮小地圖,讓資料顯示到螢幕中
System.out.println("縮小地圖1:" + min_x + "," + pix_lng);
mapController.setZoom(mapView.getZoomLevel() - 1);
pix_lng = mapView.getProjection().fromPixels(0, 0)
.getLongitudeE6() / 1E6;
pix_lat = mapView.getProjection().fromPixels(0, 0)
.getLatitudeE6() / 1E6;
}
while (max_y > pix_lat) {// 資料中最大緯度如果大於螢幕所對應的最小緯度(出界),則縮小地圖,讓資料顯示到螢幕中
System.out.println("縮小地圖2");
mapController.setZoom(mapView.getZoomLevel() - 1);
pix_lat = mapView.getProjection().fromPixels(0, 0)
.getLatitudeE6() / 1E6;
}
System.out.println("mapView的值:" + mapView.getHeight());
}
}
剛才那段代碼改成:
Java代碼
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
comList = this.getComList();//擷取網路攝影機資料
mapView = (MapView) findViewById(R.id.MapView01);
mapView.setStreetView(true);
mapView.setEnabled(true);
mapView.setClickable(true);
mapView.setBuiltInZoomControls(true); // 設定地圖支援縮放
System.out.println("長和寬:"+mapView.getHeight()+","+mapView.getWidth());
mapController = (MapController)mapView.getController();
// locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 位置管理器
// 設定地圖中心點
Double lat1 = (min_y + max_y) / 2 * 1E6;
Double lng1 = (min_x + max_x) / 2 * 1E6;
System.out.println("中心點:"+lat1+","+lng1);
GeoPoint geoPoint = new GeoPoint(lat1.intValue(), lng1.intValue());
mapController.setCenter(geoPoint);
mapController.setZoom(16);
...
Drawable defaultMarker = getResources().getDrawable(R.drawable.arrow);
Drawable activeMarker = getResources().getDrawable(R.drawable.icon);
defaultMarker.setBounds(0, 0, defaultMarker.getMinimumWidth(),
defaultMarker.getMinimumHeight());
PositionsOverlay posOverlay = new PositionsOverlay(defaultMarker,
comList, activeMarker,this);
List<Overlay> overlays = getMapView().getOverlays();
overlays.add(posOverlay);
//啟動新的線程來監視mapView是否渲染完畢,渲染完畢則開始調整mapView的縮放水平以適合全部資料
SelfAdaptionMapView cv = new SelfAdaptionMapView(mapView,max_x,min_y,min_x,max_y);
new Thread(cv).start();