• Android 百度地图开发(三)--- 实现比例尺功能和替换自带的缩放组件


    转载请注明出处: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类的代码如下

    <span style="font-family:System;font-size:12px;">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();
        }
    
    }</span>

    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" />

    运行结果

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

    上面的代码有些东西没有贴出来,有兴趣的朋友可以下载源码项目源码,点击下载

  • 相关阅读:
    PHP做ERP, CRM, CMS系统需要注意哪些地方
    java封装小实例
    java中数组的数组问题
    switch语句小练习
    java交换两个变量值a,b的多钟方法
    java中 i = i++ 的结果
    每日java基础知识(01)
    计算机存储负数以及int转byte时-128的出现
    python RSA 加密
    CentOS 7 安装 建立svn仓库 远程连接
  • 原文地址:https://www.cnblogs.com/a354823200/p/4105147.html
Copyright © 2020-2023  润新知