• Android 百度地图开发(三)


    实现比例尺功能和替换自带的缩放组件


    ScaleView是比例尺控件。ZoomControlView是缩放控件,MainActivity就是我们的主界面了


    先看下ZoomControlView类。代码例如以下

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    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的缩放级别更新缩放button的状态。当达到最大缩放级别,设置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.   
    94. }  


    这个类封装好了地图的缩放功能,里面主要是两个button,一个button是放大MapView。当放大到了MapView的最大缩放级别,设置此button的Enable为false,还有一个button缩小MapView,当缩小到了MapView最小的缩放级别,设置此button的Enable为false。refreshZoomButtonStatus()方法就是实现了此功能,我们依据MapView的缩放级别来更新button的状态,我们还必须调用setMapView(MapView mapView)方法来设置ZoomControlView与MapView关联,ZoomControlView的布局文件zoom_controls_layout我就不贴出来了,里面就两个button,然后给button设置背景选择器seletor


    ScaleView类的代码例如以下

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. <span style="font-family:System;font-size:12px;">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 = {205010020050010002000,  
    53.             5000100002000025000500001000002000005000001000000,  
    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.   
    256. }</span>  

    ScaleView是比例尺控件类,主要是提供比例尺的绘制功能,在onDraw(Canvas canvas)的方法中绘制上面的距离和以下的比例尺长度。这里面要说下drawNinepath()方法,由于我们的比例尺图片是.9.png格式的,保证图片拉伸状态下不变形,假设用寻常绘制一般图片的方法会报ClassCastException。所以我们能够利用drawNinepath()来手动绘制.9.png格式的图片。我们比例尺的长度是变化的。我们须要将以米为计量单位的距离(沿赤道)在当前缩放水平下转换到一个以像素(水平)为计量单位的距离,meterToPixels()方法依据我们MapView当前的缩放级别,得出比例尺图标应该显示多长。refreshScaleView()是用来更新ScaleView的,更新上面的字符串和以下比例尺的长度,当然我们也必须调用setMapView(MapView mapView)方法来设置ScaleView与MapView关联


    接下来我们就来使用我们的比例尺控件和缩放控件了,先看下布局

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    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的代码例如以下

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    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.              * 动画结束时会回调此消息.我们在此方法里面更新缩放button的状态 
    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.         //更新缩放button的状态  
    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.   
    162. }  

    主界面的代码还是比較简单的。主要是利用MapView的regMapViewListener()来注冊地图显示事件监听器。

    该接口监听地图显示事件。用户须要实现该接口以处理对应事件,分别在回调方法onMapAnimationFinish()和onMapMoveFinish()来更新ZoomControlView和ScaleView的一些状态

    在执行之前须要在Manifest中增加相相应的权限问题

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    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" />  

    执行结果



    好了,今天的解说到此结束。有疑问的朋友请在以下留言!




  • 相关阅读:
    SSRS中加入书签功能及数据集窗口
    Oracle 语法
    DOM基本操作
    文字横向滚动和垂直向上滚动
    offsetWidth和width的区别
    css3动画(animation)效果3-正方体合成
    css3动画(animation)效果2-旋转的星球
    css3动画(animation)效果1-漂浮的白云
    JavaScript 错误监控Fundebug
    第二篇:git创建流程
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/5092154.html
Copyright © 2020-2023  润新知