zoukankan      html  css  js  c++  java
  • 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" />

    运行结果

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

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

  • 相关阅读:
    es5预览本地文件、es6练习代码演示案例
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 836 矩形重叠(暴力)
    Subversion under Linux [Reprint]
    Subversion how[Reprint]
  • 原文地址:https://www.cnblogs.com/a354823200/p/4105147.html
Copyright © 2011-2022 走看看