Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android百度地圖開發教程(三)實現比例尺功能和縮放功能

Android百度地圖開發教程(三)實現比例尺功能和縮放功能

編輯:Android開發實例

 先看下項目工程結構


ScaleView是比例尺控件,ZoomControlView是縮放控件,MainActivity就是我們的主界面了

 


先看下ZoomControlView類,代碼如下

 

  1. package com.example.baidumapdemo;  
  2.  
  3. import com.baidu.mapapi.map.MapView;  
  4.  
  5. import android.content.Context;  
  6. import android.util.AttributeSet;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.widget.Button;  
  10. import android.widget.RelativeLayout;  
  11. import android.view.View.OnClickListener;  
  12.  
  13. public class ZoomControlView extends RelativeLayout implements OnClickListener{  
  14.     private Button mButtonZoomin;  
  15.     private Button mButtonZoomout;  
  16.     private MapView mapView;  
  17.     private int maxZoomLevel;  
  18.     private int minZoomLevel;  
  19.       
  20.     public ZoomControlView(Context context, AttributeSet attrs) {  
  21.         this(context, attrs, 0);  
  22.     }  
  23.  
  24.     public ZoomControlView(Context context, AttributeSet attrs, int defStyle) {  
  25.         super(context, attrs, defStyle);  
  26.         init();  
  27.     }  
  28.  
  29.       
  30.     private void init() {  
  31.         View view = LayoutInflater.from(getContext()).inflate(R.layout.zoom_controls_layout, null);  
  32.         mButtonZoomin = (Button) view.findViewById(R.id.zoomin);  
  33.         mButtonZoomout = (Button) view.findViewById(R.id.zoomout);  
  34.         mButtonZoomin.setOnClickListener(this);  
  35.         mButtonZoomout.setOnClickListener(this);  
  36.         addView(view);  
  37.     }  
  38.  
  39.     @Override 
  40.     public void onClick(View v) {  
  41.         if(mapView == null){  
  42.             throw new NullPointerException("you can call setMapView(MapView mapView) at first");  
  43.         }  
  44.         switch (v.getId()) {  
  45.         case R.id.zoomin:{  
  46.             mapView.getController().zoomIn();  
  47.             break;  
  48.         }  
  49.         case R.id.zoomout:{  
  50.             mapView.getController().zoomOut();  
  51.             break;  
  52.         }  
  53.         }  
  54.     }  
  55.  
  56.     /**  
  57.      * 與MapView設置關聯  
  58.      * @param mapView  
  59.      */ 
  60.     public void setMapView(MapView mapView) {  
  61.         this.mapView = mapView;  
  62.         // 獲取最大的縮放級別  
  63.         maxZoomLevel = mapView.getMaxZoomLevel();  
  64.         // 獲取最大的縮放級別  
  65.         minZoomLevel = mapView.getMinZoomLevel();  
  66.     }  
  67.       
  68.       
  69.     /**  
  70.      * 根據MapView的縮放級別更新縮放按鈕的狀態,當達到最大縮放級別,設置mButtonZoomin  
  71.      * 為不能點擊,反之設置mButtonZoomout  
  72.      * @param level  
  73.      */ 
  74.     public void refreshZoomButtonStatus(int level){  
  75.         if(mapView == null){  
  76.             throw new NullPointerException("you can call setMapView(MapView mapView) at first");  
  77.         }  
  78.         if(level > minZoomLevel && level < maxZoomLevel){  
  79.             if(!mButtonZoomout.isEnabled()){  
  80.                 mButtonZoomout.setEnabled(true);  
  81.             }  
  82.             if(!mButtonZoomin.isEnabled()){   
  83.                 mButtonZoomin.setEnabled(true);  
  84.             }  
  85.         }  
  86.         else if(level == minZoomLevel ){  
  87.             mButtonZoomout.setEnabled(false);  
  88.         }  
  89.         else if(level == maxZoomLevel){  
  90.             mButtonZoomin.setEnabled(false);  
  91.         }  
  92.     }  
  93.  

這個類封裝好了地圖的縮放功能,裡面主要是兩個按鈕,一個按鈕是放大MapView,當放大到了MapView的最大縮放級別,設置此按鈕的Enable為false,另一個按鈕縮小MapView,當縮小到了MapView最小的縮放級別,設置此按鈕的Enable為false,refreshZoomButtonStatus()方法就是實現了此功能,我們根據MapView的縮放級別來更新按鈕的狀態,我們還必須調用setMapView(MapView mapView)方法來設置ZoomControlView與MapView關聯,ZoomControlView的布局文件zoom_controls_layout我就不貼出來了,裡面就兩個按鈕,然後給按鈕設置背景選擇器seletor

 

ScaleView類的代碼如下

  1. package com.example.baidumapdemo;  
  2.  
  3. import com.baidu.mapapi.map.MapView;  
  4. import com.baidu.platform.comapi.basestruct.GeoPoint;  
  5.  
  6. import android.annotation.SuppressLint;  
  7. import android.content.Context;  
  8. import android.graphics.Bitmap;  
  9. import android.graphics.BitmapFactory;  
  10. import android.graphics.Canvas;  
  11. import android.graphics.Color;  
  12. import android.graphics.NinePatch;  
  13. import android.graphics.Paint;  
  14. import android.graphics.Rect;  
  15. import android.graphics.Typeface;  
  16. import android.util.AttributeSet;  
  17. import android.view.View;  
  18.  
  19. public class ScaleView extends View {  
  20.     private Paint mPaint;  
  21.     /**  
  22.      * 比例尺的寬度  
  23.      */ 
  24.     private int scaleWidth;  
  25.     /**  
  26.      * 比例尺的高度  
  27.      */ 
  28.     private int scaleHeight = 4;  
  29.     /**  
  30.      * 比例尺上面字體的顏色  
  31.      */ 
  32.     private int textColor = Color.BLACK;  
  33.     /**  
  34.      * 比例尺上邊的字體  
  35.      */ 
  36.     private String text;  
  37.     /**  
  38.      * 字體大小  
  39.      */ 
  40.     private int textSize = 16;  
  41.     /**  
  42.      * 比例尺與字體間的距離  
  43.      */ 
  44.     private int scaleSpaceText = 8;  
  45.     /**  
  46.      * 百度地圖最大縮放級別  
  47.      */ 
  48.     private static final int MAX_LEVEL = 19;  
  49.     /**  
  50.      * 各級比例尺分母值數組  
  51.      */ 
  52.     private static final int[] SCALES = {20, 50, 100, 200, 500, 1000, 2000,  
  53.             5000, 10000, 20000, 25000, 50000, 100000, 200000, 500000, 1000000,  
  54.             2000000 };  
  55.     /**  
  56.      * 各級比例尺上面的文字數組  
  57.      */ 
  58.     private static final String[] SCALE_DESCS = { "20米", "50米", "100米", "200米",  
  59.             "500米", "1公裡", "2公裡", "5公裡", "10公裡", "20公裡", "25公裡", "50公裡",  
  60.             "100公裡", "200公裡", "500公裡", "1000公裡", "2000公裡" };  
  61.       
  62.     private MapView mapView;  
  63.       
  64.       
  65.  
  66.     /**  
  67.      * 與MapView設置關聯  
  68.      * @param mapView  
  69.      */ 
  70.     public void setMapView(MapView mapView) {  
  71.         this.mapView = mapView;  
  72.     }  
  73.  
  74.     public ScaleView(Context context) {  
  75.         this(context, null);  
  76.     }  
  77.       
  78.     public ScaleView(Context context, AttributeSet attrs) {  
  79.         this(context, attrs, 0);  
  80.     }  
  81.  
  82.     public ScaleView(Context context, AttributeSet attrs, int defStyle) {  
  83.         super(context, attrs, defStyle);  
  84.         mPaint = new Paint();  
  85.     }  
  86.  
  87.       
  88.     /**  
  89.      * 繪制上面的文字和下面的比例尺,因為比例尺是.9.png,我們需要利用drawNinepath方法繪制比例尺  
  90.      */ 
  91.     @SuppressLint("DrawAllocation")  
  92.     @Override 
  93.     protected void onDraw(Canvas canvas) {  
  94.         super.onDraw(canvas);  
  95.           
  96.         int width = scaleWidth;  
  97.           
  98.         mPaint.setColor(textColor);  
  99.         mPaint.setAntiAlias(true);  
  100.         mPaint.setTextSize(textSize);  
  101.         mPaint.setTypeface(Typeface.DEFAULT_BOLD);  
  102.         float textWidth = mPaint.measureText(text);  
  103.           
  104.         canvas.drawText(text, (width - textWidth) / 2, textSize, mPaint);  
  105.           
  106.         Rect scaleRect = new Rect(0, textSize + scaleSpaceText, scaleWidth, textSize + scaleSpaceText + scaleHeight);  
  107.         drawNinepath(canvas, R.drawable.icon_scale, scaleRect);  
  108.     }  
  109.       
  110.     /**  
  111.      * 手動繪制.9.png圖片  
  112.      * @param canvas  
  113.      * @param resId  
  114.      * @param rect  
  115.      */ 
  116.     private void drawNinepath(Canvas canvas, int resId, Rect rect){    
  117.         Bitmap bmp= BitmapFactory.decodeResource(getResources(), resId);    
  118.         NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);    
  119.         patch.draw(canvas, rect);    
  120.     }  
  121.  
  122.       
  123.  
  124.     /**  
  125.      * 測量ScaleView的方法,  
  126.      */ 
  127.     @Override 
  128.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  129.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  130.         int widthSize = getWidthSize(widthMeasureSpec);  
  131.         int heightSize = getHeightSize(heightMeasureSpec);  
  132.         setMeasuredDimension(widthSize, heightSize);  
  133.     }  
  134.       
  135.     /**  
  136.      * 測量ScaleView的寬度  
  137.      * @param widthMeasureSpec  
  138.      * @return  
  139.      */ 
  140.     private int getWidthSize(int widthMeasureSpec){  
  141.         return MeasureSpec.getSize(widthMeasureSpec);  
  142.     }  
  143.       
  144.     /**  
  145.      * 測量ScaleView的高度  
  146.      * @param widthMeasureSpec  
  147.      * @return  
  148.      */ 
  149.     private int getHeightSize(int heightMeasureSpec){  
  150.         int mode = MeasureSpec.getMode(heightMeasureSpec);  
  151.         int height = 0;  
  152.         switch (mode) {  
  153.         case MeasureSpec.AT_MOST:  
  154.             height = textSize + scaleSpaceText + scaleHeight;  
  155.             break;  
  156.         case MeasureSpec.EXACTLY:{  
  157.             height = MeasureSpec.getSize(heightMeasureSpec);  
  158.             break;  
  159.         }  
  160.         case MeasureSpec.UNSPECIFIED:{  
  161.             height = Math.max(textSize + scaleSpaceText + scaleHeight, MeasureSpec.getSize(heightMeasureSpec));  
  162.             break;  
  163.         }  
  164.         }  
  165.           
  166.         return height;  
  167.     }  
  168.       
  169.     /**  
  170.      * 根據縮放級別,得到對應比例尺在SCALES數組中的位置(索引)  
  171.      * @param zoomLevel  
  172.      * @return  
  173.      */ 
  174.     private static int getScaleIndex(int zoomLevel) {  
  175.         return MAX_LEVEL - zoomLevel;  
  176.     }  
  177.  
  178.     /**  
  179.      * 根據縮放級別,得到對應比例尺  
  180.      *   
  181.      * @param zoomLevel  
  182.      * @return  
  183.      */ 
  184.     public static int getScale(int zoomLevel) {  
  185.         return SCALES[getScaleIndex(zoomLevel)];  
  186.     }  
  187.  
  188.     /**  
  189.      *  根據縮放級別,得到對應比例尺文字  
  190.      * @param zoomLevel  
  191.      * @return  
  192.      */ 
  193.     public static String getScaleDesc(int zoomLevel) {  
  194.         return SCALE_DESCS[getScaleIndex(zoomLevel)];  
  195.     }  
  196.  
  197.       
  198.     /**  
  199.      * 根據地圖當前中心位置的緯度,當前比例尺,得出比例尺圖標應該顯示多長(多少像素)  
  200.      * @param map  
  201.      * @param scale  
  202.      * @return  
  203.      */ 
  204.     public static int meterToPixels(MapView map, int scale) {  
  205.         // 得到當前中心位置對象  
  206.         GeoPoint geoPoint = map.getMapCenter();  
  207.         // 得到當前中心位置緯度  
  208.         double latitude = geoPoint.getLatitudeE6() / 1E6;  
  209.         // 得到象素數,比如當前比例尺是1/10000,比如scale=10000,對應在該緯度應在地圖中繪多少象素  
  210.         // 參考http://rainbow702.iteye.com/blog/1124244  
  211.         return (int) (map.getProjection().metersToEquatorPixels(scale) / (Math  
  212.                 .cos(Math.toRadians(latitude))));  
  213.           
  214.           
  215.     }  
  216.  
  217.     /**  
  218.      * 設置比例尺的寬度  
  219.      * @param scaleWidth  
  220.      */ 
  221.     public  void setScaleWidth(int scaleWidth) {  
  222.         this.scaleWidth = scaleWidth;  
  223.     }  
  224.  
  225.     /**  
  226.      * 設置比例尺的上面的 text 例如 200公裡  
  227.      * @param text  
  228.      */ 
  229.     private void setText(String text) {  
  230.         this.text = text;  
  231.     }  
  232.  
  233.     /**  
  234.      * 設置字體大小  
  235.      * @param textSize  
  236.      */ 
  237.     public void setTextSize(int textSize) {  
  238.         this.textSize = textSize;  
  239.         invalidate();  
  240.     }  
  241.       
  242.       
  243.     /**  
  244.      * 根據縮放級別更新ScaleView的文字以及比例尺的長度  
  245.      * @param level  
  246.      */ 
  247.     public void refreshScaleView(int level) {  
  248.         if(mapView == null){  
  249.             throw new NullPointerException("you can call setMapView(MapView mapView) at first");  
  250.         }  
  251.         setText(getScaleDesc(level));  
  252.         setScaleWidth(meterToPixels(mapView, getScale(level)));  
  253.         invalidate();  
  254.     }  
  255.  

ScaleView是比例尺控件類,主要是提供比例尺的繪制功能,在onDraw(Canvas canvas)的方法中繪制上面的距離和下面的比例尺長度,這裡面要說下drawNinepath()方法,因為我們的比例尺圖片是.9.png格式的,保證圖片拉伸狀態下不變形,如果用平常繪制一般圖片的方法會報ClassCastException,所以我們可以利用drawNinepath()來手動繪制.9.png格式的圖片,我們比例尺的長度是變化的,我們需要將以米為計量單位的距離(沿赤道)在當前縮放水平下轉換到一個以像素(水平)為計量單位的距離,meterToPixels()方法根據我們MapView當前的縮放級別,得出比例尺圖標應該顯示多長,refreshScaleView()是用來更新ScaleView的,更新上面的字符串和下面比例尺的長度,當然我們也必須調用setMapView(MapView mapView)方法來設置ScaleView與MapView關聯

 


接下來我們就來使用我們的比例尺控件和縮放控件了,先看下布局

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="fill_parent" 
  4.     android:layout_height="fill_parent" > 
  5.  
  6.     <com.baidu.mapapi.map.MapView 
  7.         android:id="@+id/bmapView" 
  8.         android:layout_width="fill_parent" 
  9.         android:layout_height="fill_parent" 
  10.         android:clickable="true" /> 
  11.  
  12.     <com.example.baidumapdemo.ZoomControlView 
  13.         android:id="@+id/ZoomControlView" 
  14.         android:layout_width="wrap_content" 
  15.         android:layout_height="wrap_content" 
  16.         android:layout_alignParentBottom="true" 
  17.         android:layout_alignParentRight="true" 
  18.         android:layout_marginBottom="20.0dip" 
  19.         android:layout_marginRight="5.0dip"/> 
  20.  
  21.     <com.example.baidumapdemo.ScaleView 
  22.         android:id="@+id/scaleView" 
  23.         android:layout_width="wrap_content" 
  24.         android:layout_height="wrap_content" 
  25.         android:layout_alignParentBottom="true" 
  26.         android:layout_alignParentLeft="true" 
  27.         android:layout_marginBottom="40dp" 
  28.         android:layout_marginLeft="20dp" /> 
  29.  
  30. </RelativeLayout> 

 

主界面MainActivity的代碼如下

  1. package com.example.baidumapdemo;  
  2.  
  3. import android.app.Activity;  
  4. import android.graphics.Bitmap;  
  5. import android.os.Bundle;  
  6. import android.widget.Toast;  
  7.  
  8. import com.baidu.mapapi.BMapManager;  
  9. import com.baidu.mapapi.MKGeneralListener;  
  10. import com.baidu.mapapi.map.MKEvent;  
  11. import com.baidu.mapapi.map.MKMapViewListener;  
  12. import com.baidu.mapapi.map.MapController;  
  13. import com.baidu.mapapi.map.MapPoi;  
  14. import com.baidu.mapapi.map.MapView;  
  15. import com.baidu.platform.comapi.basestruct.GeoPoint;  
  16.  
  17. public class MainActivity extends Activity{  
  18.     private BMapManager mBMapManager;  
  19.     /**  
  20.      * MapView 是地圖主控件  
  21.      */ 
  22.     private MapView mMapView = null;  
  23.     /**  
  24.      * 用MapController完成地圖控制  
  25.      */ 
  26.     private MapController mMapController = null;  
  27.       
  28.     private ScaleView mScaleView;  
  29.     private ZoomControlView mZoomControlView;  
  30.       
  31.     @Override 
  32.     protected void onCreate(Bundle savedInstanceState) {  
  33.         super.onCreate(savedInstanceState);  
  34.           
  35.         //使用地圖sdk前需先初始化BMapManager,這個必須在setContentView()先初始化  
  36.         mBMapManager = new BMapManager(this);  
  37.           
  38.         //第一個參數是API key,  
  39.         //第二個參數是常用事件監聽,用來處理通常的網絡錯誤,授權驗證錯誤等,你也可以不添加這個回調接口  
  40.         mBMapManager.init("CC61ac7527b65c95899608810873b173", new MKGeneralListener() {  
  41.               
  42.             //授權錯誤的時候調用的回調函數  
  43.             @Override 
  44.             public void onGetPermissionState(int iError) {  
  45.                 if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {  
  46.                     Toast.makeText(getApplication(), "API Key錯誤,請檢查!",  
  47.                             Toast.LENGTH_LONG).show();  
  48.                 }  
  49.             }  
  50.               
  51.             //一些網絡狀態的錯誤處理回調函數  
  52.             @Override 
  53.             public void onGetNetworkState(int iError) {  
  54.                 if (iError == MKEvent.ERROR_NETWORK_CONNECT) {  
  55.                     Toast.makeText(getApplication(), "您的網絡出錯啦!",  
  56.                         Toast.LENGTH_LONG).show();  
  57.                 }  
  58.             }  
  59.         });  
  60.           
  61.         setContentView(R.layout.activity_main);  
  62.         mMapView = (MapView) findViewById(R.id.bmapView);  
  63.         //隱藏自帶的地圖縮放控件  
  64.         mMapView.setBuiltInZoomControls(false);  
  65.           
  66.         mScaleView = (ScaleView) findViewById(R.id.scaleView);  
  67.         mScaleView.setMapView(mMapView);  
  68.         mZoomControlView = (ZoomControlView) findViewById(R.id.ZoomControlView);  
  69.         mZoomControlView.setMapView(mMapView);  
  70.           
  71.           
  72.         //地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件。  
  73.         mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() {  
  74.               
  75.             @Override 
  76.             public void onMapMoveFinish() {  
  77.                  refreshScaleAndZoomControl();  
  78.             }  
  79.               
  80.             @Override 
  81.             public void onMapLoadFinish() {  
  82.                   
  83.             }  
  84.               
  85.               
  86.               
  87.             /**  
  88.              * 動畫結束時會回調此消息.我們在此方法裡面更新縮放按鈕的狀態  
  89.              */ 
  90.             @Override 
  91.             public void onMapAnimationFinish() {  
  92.                  refreshScaleAndZoomControl();  
  93.             }  
  94.               
  95.             @Override 
  96.             public void onGetCurrentMap(Bitmap arg0) {  
  97.                   
  98.             }  
  99.               
  100.             @Override 
  101.             public void onClickMapPoi(MapPoi arg0) {  
  102.                   
  103.             }  
  104.         });  
  105.           
  106.         //獲取地圖控制器  
  107.         mMapController = mMapView.getController();  
  108.         //設置地圖是否響應點擊事件  .  
  109.         mMapController.enableClick(true);  
  110.         //設置地圖縮放級別  
  111.         mMapController.setZoom(14);  
  112.           
  113.         refreshScaleAndZoomControl();  
  114.           
  115.         //保存精度和緯度的類,  
  116.         GeoPoint p = new GeoPoint((int)(22.547923 * 1E6), (int)(114.067368 * 1E6));  
  117.         //設置p地方為中心點  
  118.         mMapController.setCenter(p);  
  119.           
  120.     }  
  121.  
  122.       
  123.       
  124.     private void refreshScaleAndZoomControl(){  
  125.         //更新縮放按鈕的狀態  
  126.         mZoomControlView.refreshZoomButtonStatus(Math.round(mMapView.getZoomLevel()));  
  127.         mScaleView.refreshScaleView(Math.round(mMapView.getZoomLevel()));  
  128.     }  
  129.       
  130.       
  131.     @Override 
  132.     protected void onResume() {  
  133.         //MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()  
  134.         mMapView.onResume();  
  135.         super.onResume();  
  136.     }  
  137.  
  138.  
  139.  
  140.     @Override 
  141.     protected void onPause() {  
  142.         //MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()  
  143.         mMapView.onPause();  
  144.         super.onPause();  
  145.     }  
  146.  
  147.     @Override 
  148.     protected void onDestroy() {  
  149.         //MapView的生命周期與Activity同步,當activity銷毀時需調用MapView.destroy()  
  150.         mMapView.destroy();  
  151.           
  152.         //退出應用調用BMapManager的destroy()方法  
  153.         if(mBMapManager != null){  
  154.             mBMapManager.destroy();  
  155.             mBMapManager = null;  
  156.         }  
  157.           
  158.         super.onDestroy();  
  159.           
  160.     }  
  161.  

主界面的代碼還是比較簡單的,主要是利用MapView的regMapViewListener()來注冊地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件,分別在回調方法onMapAnimationFinish()和onMapMoveFinish()來更新ZoomControlView和ScaleView的一些狀態


在運行之前需要在Manifest中加入相對應的權限問題

  1. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    
  2. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />    
  3. <uses-permission android:name="android.permission.INTERNET" />    
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
  5. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    
  6. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />    
  7. <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

 

運行結果

 

 

源碼下載

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved