轉載請注明出處: http://blog.csdn.net/xiaanming/article/details/11821523
貌似有些天沒有寫博客了,前段時間在忙找工作的事,面試了幾家公司,表示反響還不錯,過完國慶節去新公司報道,期待新的公司,新的同事,而且新公司還有很多女孩子,哈哈,我可是一年多沒和女孩子一起工作過了,之前的公司全是男的,你沒聽錯,真的全是男的,我還以為我自己不會在愛了,現在Android市場還可以,想要跳槽換工作的趕緊,過了這個村就沒這個店了,還有就是恭喜自己成了博客專家了,很開心也很感謝CSDN給我這份榮譽,我會繼續寫出對大家有用的博文,感謝大家的支持,今天繼續給大家帶來百度地圖開發系列三 ,實現比例尺功能和替換自帶的縮放組件,先看下項目工程結構
ScaleView是比例尺控件,ZoomControlView是縮放控件,MainActivity就是我們的主界面了
先看下ZoomControlView類,代碼如下
package com.example.baidumapdemo;
import com.baidu.mapapi.map.MapView;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.view.View.OnClickListener;
public class ZoomControlView extends RelativeLayout implements OnClickListener{
private Button mButtonZoomin;
private Button mButtonZoomout;
private MapView mapView;
private int maxZoomLevel;
private int minZoomLevel;
public ZoomControlView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ZoomControlView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
View view = LayoutInflater.from(getContext()).inflate(R.layout.zoom_controls_layout, null);
mButtonZoomin = (Button) view.findViewById(R.id.zoomin);
mButtonZoomout = (Button) view.findViewById(R.id.zoomout);
mButtonZoomin.setOnClickListener(this);
mButtonZoomout.setOnClickListener(this);
addView(view);
}
@Override
public void onClick(View v) {
if(mapView == null){
throw new NullPointerException("you can call setMapView(MapView mapView) at first");
}
switch (v.getId()) {
case R.id.zoomin:{
mapView.getController().zoomIn();
break;
}
case R.id.zoomout:{
mapView.getController().zoomOut();
break;
}
}
}
/**
* 與MapView設置關聯
* @param mapView
*/
public void setMapView(MapView mapView) {
this.mapView = mapView;
// 獲取最大的縮放級別
maxZoomLevel = mapView.getMaxZoomLevel();
// 獲取最大的縮放級別
minZoomLevel = mapView.getMinZoomLevel();
}
/**
* 根據MapView的縮放級別更新縮放按鈕的狀態,當達到最大縮放級別,設置mButtonZoomin
* 為不能點擊,反之設置mButtonZoomout
* @param level
*/
public void refreshZoomButtonStatus(int level){
if(mapView == null){
throw new NullPointerException("you can call setMapView(MapView mapView) at first");
}
if(level > minZoomLevel && level < maxZoomLevel){
if(!mButtonZoomout.isEnabled()){
mButtonZoomout.setEnabled(true);
}
if(!mButtonZoomin.isEnabled()){
mButtonZoomin.setEnabled(true);
}
}
else if(level == minZoomLevel ){
mButtonZoomout.setEnabled(false);
}
else if(level == maxZoomLevel){
mButtonZoomin.setEnabled(false);
}
}
}
這個類封裝好了地圖的縮放功能,里面主要是兩個按鈕,一個按鈕是放大MapView,當放大到了MapView的最大縮放級別,設置此按鈕的Enable為false,另一個按鈕縮小MapView,當縮小到了MapView最小的縮放級別,設置此按鈕的Enable為false,refreshZoomButtonStatus()方法就是實現了此功能,我們根據MapView的縮放級別來更新按鈕的狀態,我們還必須調用setMapView(MapView mapView)方法來設置ZoomControlView與MapView關聯,ZoomControlView的布局文件zoom_controls_layout我就不貼出來了,里面就兩個按鈕,然后給按鈕設置背景選擇器seletor
ScaleView類的代碼如下
package com.example.baidumapdemo;
import com.baidu.mapapi.map.MapView;
import com.baidu.platform.comapi.basestruct.GeoPoint;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
public class ScaleView extends View {
private Paint mPaint;
/**
* 比例尺的寬度
*/
private int scaleWidth;
/**
* 比例尺的高度
*/
private int scaleHeight = 4;
/**
* 比例尺上面字體的顏色
*/
private int textColor = Color.BLACK;
/**
* 比例尺上邊的字體
*/
private String text;
/**
* 字體大小
*/
private int textSize = 16;
/**
* 比例尺與字體間的距離
*/
private int scaleSpaceText = 8;
/**
* 百度地圖最大縮放級別
*/
private static final int MAX_LEVEL = 19;
/**
* 各級比例尺分母值數組
*/
private static final int[] SCALES = {20, 50, 100, 200, 500, 1000, 2000,
5000, 10000, 20000, 25000, 50000, 100000, 200000, 500000, 1000000,
2000000 };
/**
* 各級比例尺上面的文字數組
*/
private static final String[] SCALE_DESCS = { "20米", "50米", "100米", "200米",
"500米", "1公里", "2公里", "5公里", "10公里", "20公里", "25公里", "50公里",
"100公里", "200公里", "500公里", "1000公里", "2000公里" };
private MapView mapView;
/**
* 與MapView設置關聯
* @param mapView
*/
public void setMapView(MapView mapView) {
this.mapView = mapView;
}
public ScaleView(Context context) {
this(context, null);
}
public ScaleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
}
/**
* 繪制上面的文字和下面的比例尺,因為比例尺是.9.png,我們需要利用drawNinepath方法繪制比例尺
*/
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = scaleWidth;
mPaint.setColor(textColor);
mPaint.setAntiAlias(true);
mPaint.setTextSize(textSize);
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
float textWidth = mPaint.measureText(text);
canvas.drawText(text, (width - textWidth) / 2, textSize, mPaint);
Rect scaleRect = new Rect(0, textSize + scaleSpaceText, scaleWidth, textSize + scaleSpaceText + scaleHeight);
drawNinepath(canvas, R.drawable.icon_scale, scaleRect);
}
/**
* 手動繪制.9.png圖片
* @param canvas
* @param resId
* @param rect
*/
private void drawNinepath(Canvas canvas, int resId, Rect rect){
Bitmap bmp= BitmapFactory.decodeResource(getResources(), resId);
NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);
patch.draw(canvas, rect);
}
/**
* 測量ScaleView的方法,
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = getWidthSize(widthMeasureSpec);
int heightSize = getHeightSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
/**
* 測量ScaleView的寬度
* @param widthMeasureSpec
* @return
*/
private int getWidthSize(int widthMeasureSpec){
return MeasureSpec.getSize(widthMeasureSpec);
}
/**
* 測量ScaleView的高度
* @param widthMeasureSpec
* @return
*/
private int getHeightSize(int heightMeasureSpec){
int mode = MeasureSpec.getMode(heightMeasureSpec);
int height = 0;
switch (mode) {
case MeasureSpec.AT_MOST:
height = textSize + scaleSpaceText + scaleHeight;
break;
case MeasureSpec.EXACTLY:{
height = MeasureSpec.getSize(heightMeasureSpec);
break;
}
case MeasureSpec.UNSPECIFIED:{
height = Math.max(textSize + scaleSpaceText + scaleHeight, MeasureSpec.getSize(heightMeasureSpec));
break;
}
}
return height;
}
/**
* 根據縮放級別,得到對應比例尺在SCALES數組中的位置(索引)
* @param zoomLevel
* @return
*/
private static int getScaleIndex(int zoomLevel) {
return MAX_LEVEL - zoomLevel;
}
/**
* 根據縮放級別,得到對應比例尺
*
* @param zoomLevel
* @return
*/
public static int getScale(int zoomLevel) {
return SCALES[getScaleIndex(zoomLevel)];
}
/**
* 根據縮放級別,得到對應比例尺文字
* @param zoomLevel
* @return
*/
public static String getScaleDesc(int zoomLevel) {
return SCALE_DESCS[getScaleIndex(zoomLevel)];
}
/**
* 根據地圖當前中心位置的緯度,當前比例尺,得出比例尺圖標應該顯示多長(多少像素)
* @param map
* @param scale
* @return
*/
public static int meterToPixels(MapView map, int scale) {
// 得到當前中心位置對象
GeoPoint geoPoint = map.getMapCenter();
// 得到當前中心位置緯度
double latitude = geoPoint.getLatitudeE6() / 1E6;
// 得到象素數,比如當前比例尺是1/10000,比如scale=10000,對應在該緯度應在地圖中繪多少象素
// 參考http://rainbow702.iteye.com/blog/1124244
return (int) (map.getProjection().metersToEquatorPixels(scale) / (Math
.cos(Math.toRadians(latitude))));
}
/**
* 設置比例尺的寬度
* @param scaleWidth
*/
public void setScaleWidth(int scaleWidth) {
this.scaleWidth = scaleWidth;
}
/**
* 設置比例尺的上面的 text 例如 200公里
* @param text
*/
private void setText(String text) {
this.text = text;
}
/**
* 設置字體大小
* @param textSize
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
invalidate();
}
/**
* 根據縮放級別更新ScaleView的文字以及比例尺的長度
* @param level
*/
public void refreshScaleView(int level) {
if(mapView == null){
throw new NullPointerException("you can call setMapView(MapView mapView) at first");
}
setText(getScaleDesc(level));
setScaleWidth(meterToPixels(mapView, getScale(level)));
invalidate();
}
}
ScaleView是比例尺控件類,主要是提供比例尺的繪制功能,在onDraw(Canvas canvas)的方法中繪制上面的距離和下面的比例尺長度,這里面要說下drawNinepath()方法,因為我們的比例尺圖片是.9.png格式的,保證圖片拉伸狀態下不變形,如果用平常繪制一般圖片的方法會報ClassCastException,所以我們可以利用drawNinepath()來手動繪制.9.png格式的圖片,我們比例尺的長度是變化的,我們需要將 以米為計量單位的距離(沿赤道)在當前縮放水平下轉換到一個以像素(水平)為計量單位的距離,meterToPixels()方法根據我們MapView當前的縮放級別,得出比例尺圖標應該顯示多長,refreshScaleView()是用來更新ScaleView的,更新上面的字符串和下面比例尺的長度,當然 我們也必須調用setMapView(MapView mapView)方法來設置 ScaleView 與MapView關聯
接下來我們就來使用我們的比例尺控件和縮放控件了,先看下布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
<com.example.baidumapdemo.ZoomControlView
android:id="@+id/ZoomControlView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="20.0dip"
android:layout_marginRight="5.0dip"/>
<com.example.baidumapdemo.ScaleView
android:id="@+id/scaleView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="40dp"
android:layout_marginLeft="20dp" />
</RelativeLayout>
主界面MainActivity的代碼如下
package com.example.baidumapdemo;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.Toast;
import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.MKGeneralListener;
import com.baidu.mapapi.map.MKEvent;
import com.baidu.mapapi.map.MKMapViewListener;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.map.MapView;
import com.baidu.platform.comapi.basestruct.GeoPoint;
public class MainActivity extends Activity{
private BMapManager mBMapManager;
/**
* MapView 是地圖主控件
*/
private MapView mMapView = null;
/**
* 用MapController完成地圖控制
*/
private MapController mMapController = null;
private ScaleView mScaleView;
private ZoomControlView mZoomControlView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//使用地圖sdk前需先初始化BMapManager,這個必須在setContentView()先初始化
mBMapManager = new BMapManager(this);
//第一個參數是API key,
//第二個參數是常用事件監聽,用來處理通常的網絡錯誤,授權驗證錯誤等,你也可以不添加這個回調接口
mBMapManager.init("CC61ac7527b65c95899608810873b173", new MKGeneralListener() {
//授權錯誤的時候調用的回調函數
@Override
public void onGetPermissionState(int iError) {
if (iError == MKEvent.ERROR_PERMISSION_DENIED) {
Toast.makeText(getApplication(), "API Key錯誤,請檢查!",
Toast.LENGTH_LONG).show();
}
}
//一些網絡狀態的錯誤處理回調函數
@Override
public void onGetNetworkState(int iError) {
if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(getApplication(), "您的網絡出錯啦!",
Toast.LENGTH_LONG).show();
}
}
});
setContentView(R.layout.activity_main);
mMapView = (MapView) findViewById(R.id.bmapView);
//隱藏自帶的地圖縮放控件
mMapView.setBuiltInZoomControls(false);
mScaleView = (ScaleView) findViewById(R.id.scaleView);
mScaleView.setMapView(mMapView);
mZoomControlView = (ZoomControlView) findViewById(R.id.ZoomControlView);
mZoomControlView.setMapView(mMapView);
//地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件。
mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() {
@Override
public void onMapMoveFinish() {
refreshScaleAndZoomControl();
}
@Override
public void onMapLoadFinish() {
}
/**
* 動畫結束時會回調此消息.我們在此方法里面更新縮放按鈕的狀態
*/
@Override
public void onMapAnimationFinish() {
refreshScaleAndZoomControl();
}
@Override
public void onGetCurrentMap(Bitmap arg0) {
}
@Override
public void onClickMapPoi(MapPoi arg0) {
}
});
//獲取地圖控制器
mMapController = mMapView.getController();
//設置地圖是否響應點擊事件 .
mMapController.enableClick(true);
//設置地圖縮放級別
mMapController.setZoom(14);
refreshScaleAndZoomControl();
//保存精度和緯度的類,
GeoPoint p = new GeoPoint((int)(22.547923 * 1E6), (int)(114.067368 * 1E6));
//設置p地方為中心點
mMapController.setCenter(p);
}
private void refreshScaleAndZoomControl(){
//更新縮放按鈕的狀態
mZoomControlView.refreshZoomButtonStatus(Math.round(mMapView.getZoomLevel()));
mScaleView.refreshScaleView(Math.round(mMapView.getZoomLevel()));
}
@Override
protected void onResume() {
//MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()
mMapView.onResume();
super.onResume();
}
@Override
protected void onPause() {
//MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()
mMapView.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
//MapView的生命周期與Activity同步,當activity銷毀時需調用MapView.destroy()
mMapView.destroy();
//退出應用調用BMapManager的destroy()方法
if(mBMapManager != null){
mBMapManager.destroy();
mBMapManager = null;
}
super.onDestroy();
}
}
主界面的代碼還是比較簡單的,主要是利用MapView的 regMapViewListener()來注冊 地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件,分別在回調方法 onMapAnimationFinish()和 onMapMoveFinish()來更新 ZoomControlView和ScaleView的一些狀態
在運行之前需要在Manifest中加入相對應的權限問題
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
運行結果
好了,今天的講解到此結束,有疑問的朋友請在下面留言!
上面的代碼有些東西沒有貼出來,有興趣的朋友可以下載源碼 項目源碼,點擊下載
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

