Android高效率编码-第三方SDK详解系列(一)——百度地图,绘制,覆盖物,导航,定位,细腻分解!

简介: <div class="markdown_views"><h1 id="android高效率编码-第三方sdk详解系列一百度地图绘制覆盖物导航定位细腻分解">Android高效率编码-第三方SDK详解系列(一)——百度地图,绘制,覆盖物,导航,定位,细腻分解!</h1><hr><blockquote> <p>这是一个系列,但是我也不确定具体会更新多少期,最近很忙,主

Android高效率编码-第三方SDK详解系列(一)——百度地图,绘制,覆盖物,导航,定位,细腻分解!


这是一个系列,但是我也不确定具体会更新多少期,最近很忙,主要还是效率的问题,所以一些有效的东西还是会及时更新的,比如后续会出

  • 分享SDK:sharesdk
  • 后端SDK:Bmob
  • 推送SDK:极光推送
  • 短信SDK:验证码实现
  • 等等……

或者出一些装ubuntu系统或者黑苹果教程什么的,或者5.X之后的新玩法,主要还是困于时间方面缺少,或许这也是一种锻炼吧,工作了挺久的了,越发觉得自己的JAVA基础实在是烂的可以,想去买一本JAVA的书籍啃一啃,刚好年假也有15天,这都是后话了,我们言归正传,今天分析的是百度地图的sdk怎么去使用,包括他的几个类的详细说明,可能写得快的话半个礼拜就写完了就会加上高德地图什么的,不过看现在公司项目的样子,一天能写一个小时就不错了

一.百度API


百度地图API:http://developer.baidu.com/map/

api

二.搭建地图环境


1.申请百度地图的key
2.下载对应功能的sdk
3.新建一个工程导入sdk到lib里面

1.申请KEY

**我们打开百度API官网-开发-Android SDK**

这里写图片描述
然后选择获取密钥
这里写图片描述
创建应用
这里写图片描述
我们在IDE里创建一个工程–BaiDuMapDemo
然后依次填入所需要的信息
这里写图片描述
这里很多人对这个SHA1值很疑问,那我先科普一下这个是什么玩意吧
什么是SHA1?
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。 SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。
那我们该如何去获取呢?

Eclipse获取方法

eclipse

Android Studio获取方法

借鉴博文:http://blog.csdn.net/kezhongke/article/details/42678077

好了,这里注意一下,这里我用com.lgl.baidumapdemo这个包名官方提示我敏感词,所以我换了一个,本质上是没有任何影响的,不用纠结,当我们提交之后,就可以获取到key了

key

2.下载SDK

我想我不用多说什么的,这里需要自定义下载,也就是说你需要什么功能你就选择什么功能,这里做demo的话全部下载了,这里也不提供下载了,你们可以自己去下载,我把地址给出来吧:

SDK下载地址:http://developer.baidu.com/map/index.php?title=androidsdk/sdkandev-download
这里写图片描述

3.配置工程

首先我们把下载的sdk全部放在lib库里面,有点多,毕竟百度地图的功能还是可以的,不过会显得很臃肿,建议需要什么功能就放哪个架包吧,下载的时候我相关的demo和文档说明的

Eclipse

    1. 在Eclipse 中选中工程,右键选 Properties->Java Build Path->Order and Export 使 Android Private Libraries处于勾选状态;
    2. Project -> clean-> clean all 

Android Studio

    第一步:在工程app/libs目录下放入baidumapapi_vX_X_X.jar包,在src/main/目录下新建jniLibs目录,放入libBaiduMapSDK_vX_X_X_X.so如下图所示,注意jar和so的前3位版本号必须一致,并且保证使用一次下载的文件夹中的两个文件,不能不同功能组件的jar或so交叉使用。
    第二步:导入jar包。菜单栏选择File->Project Structor->Modules->Dependencies,点击+号,选择File dependency,选择jar包导入。
通过以上两步操作后,您就可以正常使用百度地图SDK为您提供的全部功能了。

这里写图片描述

三,HelloMap

1.权限

权限是必备的,而且说明文档里也十分详细的说明了

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

2.配置KEY

在application中添加开发密钥
    <meta-data  
        android:name="com.baidu.lbsapi.API_KEY"  
        android:value="开发者 key" />  

3.布局

在布局中直接添加
<com.baidu.mapapi.map.MapView  
    android:id="@+id/bmapView"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:clickable="true" />

4.初始化

在应用程序创建时初始化 SDK引用的Context 全局变量:
记住,一定要再setContentView之前执行
并且初始化mapview
    public class MainActivity extends Activity { 

    private MapView mMapView; 
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);   
        //在使用SDK各组件之前初始化context信息,传入ApplicationContext  
        //注意该方法要再setContentView方法之前实现  
        SDKInitializer.initialize(getApplicationContext());  

        mMapView = (MapView) findViewById(R.id.bmapView);  
    }  
}

5.地图的生命周期

前期工作我们都准备完成了,现在我们就把百度地图的生命周期给添加上
@Override
    protected void onDestroy() {
        super.onDestroy();
        // 在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
        mMapView.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
        mMapView.onPause();
    }

好了,准备了这么久,现在我们可以见证奇迹的时刻了

截图

map

好的,我们的初级教程到这里了,下面,就是一些高级的玩法了

四.地图进阶——基本控制

1.核心类

//三大核心类
1.BMapManager//百度地图管理工具
2.MapView   //地图控件
    ——MapView的MKMapViewListener  //控件的点击事件
3.MapController //地图控制,必须MapViewy已经存在
  //控制地图平移,缩放,选择等..

2.授权验证

我们做这种类型的应用,一般也就两个交互,一个就是key的授权,还有一个就是网络的授权了,我们我们在开始实现地图功能之前应该先去判断一下这两个条件是否实现了

实现广播机制

其实就是写个小广播,不需要很多代码
//初始化一个广播
private MyBroadcastReceiver receiver;
    class MyBroadcastReceiver extends BroadcastReceiver {
        //实现一个广播
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            // 网络错误
            if (action.equals(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR)) {
                Toast.makeText(MainActivity.this, "无法连接网络", Toast.LENGTH_SHORT).show();
                // key效验失败
            } else if(action.equals(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR)) {
                Toast.makeText(MainActivity.this, "百度地图key效验失败",Toast.LENGTH_SHORT).show();
            }
        }
    }
        //在onCreate()方法中注册广播
        receiver = new MyBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        // 网络错误
        filter.addAction(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR);
        // 效验key失败
        filter.addAction(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR);
        registerReceiver(receiver, filter);
    //注意要在onDestroy()方法中销毁这个广播
    unregisterReceiver(receiver);

广播写好了,我们来说一下这两条广播吧

逻辑就是当进入应用的时候sdk会去验证这两个条件,如果发现网络错误或者验证Key失败就会发送一条广播,广播接收者接收到了这条广播之后弹出一个Toast,当然,你如果想人性化一点也可以弹一个Dialog,这里作为demo就不做这么复杂的东西了
    //网络错误
    SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR
    //key效验失败
    SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR

3.设置地图缩放级别

虽然地图上是有按钮可以进行缩放的,但是再某些场景还是需要我们人工缩放,但是再缩放之前,我们应该先来了解一下缩放级别
缩放级别在2.X是个分水岭,在2.X之前的级别是(3-18),之后是(3-19),主要是有两个区别
1.修改了文件格式,具体是啥也不需要懂,只要知道,比如深圳的地图100M,2.x之后只要15M左右就行了
2.增加了3D效果,这要在18或者19的级别上才可以看到
我们先把BaiduMap给实现了
private BaiduMap mBaiduMap;
//在onCreate()中
mBaiduMap = mMapView.getMap();
然后我们写一个方法让onCreate()调用
private void init(){
        //描述地图将要发生的变化,使用工厂类MapStatusUpdateFactory创建,设置级别
        //为18,进去就是18了,默认是12
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.zoomTo(18); 
        mBaiduMap.setMapStatus(mapStatusUpdate);
        //是否显示缩放按钮
        //mMapView.showZoomControls(false);
    }

4.设置中心点(定位的初级实现)

你有没有发现,我们一进去地图显示的是北京天安门,其实这个就叫中心点,我们可以更改这个中心点
同样的,我们写一个方法在onCreate()中调用
private void init(){
        //经纬度(纬度,经度) 我们这里设置深圳世界之窗的位置
        LatLng latlng = new LatLng(22.5422870000,113.9804440000);
        MapStatusUpdate mapStatusUpdate_circle = MapStatusUpdateFactory.newLatLng(latlng);
        mBaiduMap.setMapStatus(mapStatusUpdate_circle);
    }

截图

现在一进去中心点就会在世界之窗的坐标点了,我们定位的实现不就是获取到坐标点然后显示嘛!嘿嘿!

世界之窗

5.地图控制器(旋转,移动,缩放)

模拟点击 模拟器上运行按12345键实现,当然,你写Button的点击事件也可以
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_1:
            //放大缩放级别,每次放大一个级别
            MapStatusUpdate bigStatus = MapStatusUpdateFactory.zoomIn();
            mBaiduMap.setMapStatus(bigStatus);
            break;
        case KeyEvent.KEYCODE_2:
            //缩小缩放级别,每次缩小一个级别
            MapStatusUpdate smallStatus = MapStatusUpdateFactory.zoomOut();
            mBaiduMap.setMapStatus(smallStatus);
            break;
        case KeyEvent.KEYCODE_3:
            //以屏幕中心点旋转
            MapStatus mapStatus = mBaiduMap.getMapStatus(); //获取当前地图的状态
            float rotate =  mapStatus.rotate;  //获取旋转角度
            Log.i("旋转角度", "rotate"+rotate);
            //用获取到的当前角度+30就是每次都旋转30°  范围0-360°
            MapStatus rotates =new MapStatus.Builder().rotate(rotate+30).build();
            //更新地图的选择
            MapStatusUpdate rotateStatus = MapStatusUpdateFactory.newMapStatus(rotates);
            mBaiduMap.setMapStatus(rotateStatus);
            break;
        case KeyEvent.KEYCODE_4:
            //以立体方式旋转
            MapStatus mapStatusOver = mBaiduMap.getMapStatus(); //获取当前地图的状态
            float overlook =  mapStatusOver.overlook;  //获取旋转角度
            Log.i("旋转角度", "overlook"+overlook);
            //弧角范围:0-45°
            MapStatus overlooks =new MapStatus.Builder().overlook(overlook-5).build();
            MapStatusUpdate overlookStatus = MapStatusUpdateFactory.newMapStatus(overlooks);
            mBaiduMap.setMapStatus(overlookStatus);
            break;
        case KeyEvent.KEYCODE_5:
            //移动
            MapStatusUpdate moveStatus = MapStatusUpdateFactory.newLatLng(new LatLng(22.5422870000, 113.9804440000));
            //带动画更新状态 默认300ms
            mBaiduMap.animateMapStatus(moveStatus);
            break;
        }

6.指南针

//显示指南针
mBaiduMap.getUiSettings().setCompassEnabled(true);
//显示位置
mBaiduMap.getUiSettings().setCompassPosition(new Point(x, y));

7.地图事件

不是很常用,地图本身都是自带点击事件的
//设置地图单击监听
mBaiduMap.setOnMapClickListener(new OnMapClickListener() {

            @Override
            public boolean onMapPoiClick(MapPoi arg0) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onMapClick(LatLng arg0) {
                // TODO Auto-generated method stub

            }
        });
//覆盖物点击事件
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {

            @Override
            public boolean onMarkerClick(Marker arg0) {
                // TODO Auto-generated method stub
                return false;
            }
        });
//设置地图双击监听
mBaiduMap.setOnMapDoubleClickListener(new OnMapDoubleClickListener() {

            @Override
            public void onMapDoubleClick(LatLng arg0) {
                // TODO Auto-generated method stub

            }
        });
//发起截图请求
mBaiduMap.snapshot(new SnapshotReadyCallback() {

            @Override
            public void onSnapshotReady(Bitmap arg0) {
                // TODO Auto-generated method stub

            }
        });

五.地图高阶——图层

1.什么是图层

一个地图是由很多个图层包裹的,还有级别,这是由图块决定的,你所看到的房子,学校什么的都是由图层实现的

2.图层分类

底图

基本的一个地图包括了各种建筑啥啥啥的

实时交通图

交通路况啥啥啥的

卫星图

就是从卫星上拍下来的嘛,哈哈哈哈,这些都一笔带过吧

其他

还有各种各样的,比如热力图啥的

3.覆盖物

覆盖物的层级压盖关系,如下(从上往下)
1、基础底图(包括底图、底图道路、卫星图等);
2、地形图图层(GroundOverlay);
3、热力图图层(HeatMap);
4、实时路况图图层(BaiduMap.setTrafficEnabled(true););
5、百度城市热力图(BaiduMap.setBaiduHeatMapEnabled(true););
6、底图标注(指的是底图上面自带的那些POI元素);
7、几何图形图层(点、折线、弧线、圆、多边形);
8、标注图层(Marker),文字绘制图层(Text);
9、指南针图层(当地图发生旋转和视角变化时,默认出现在左上角的指南针);
10、定位图层(BaiduMap.setMyLocationEnabled(true););
11、弹出窗图层(InfoWindow);
12、自定义View(MapView.addView(View););

4.基础图层切换

我们还是模拟操作,你也可以用Button点击事件去实现,这里就直接在onKeyDown()里面迷你按123键进行操作
     //点击屏幕切换图层 从地图-卫星图-交通图
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        // 底图
        case KeyEvent.KEYCODE_1:
            // 设置地图类型
            mBaiduMap.setMapType(mBaiduMap.MAP_TYPE_NORMAL);
            break;
        // 卫星图
        case KeyEvent.KEYCODE_2:
            mBaiduMap.setMapType(mBaiduMap.MAP_TYPE_SATELLITE);
            break;
        // 交通图
        case KeyEvent.KEYCODE_3:
            // 交通图是否打开
            mBaiduMap.setTrafficEnabled(true);
            break;

        }
        return super.onKeyDown(keyCode, event);
    }

5.免费申请标注

有时候我们会发现,你身处的环境附近有一些小店铺是没有在地图上标记的,也有一些小店铺就被百度地图给标记了,这是为什么了?这其实是百度的一个特有的功能,也不是技术活,纯粹就是跟申请账号一样

首先我们打开百度地图的官网:http://map.baidu.com/
map
在最下方有个不起眼的文字,商户免费标注,点进去
这里写图片描述
按照这个步骤免费申请就得了,这里就不过多赘述

六.地图高阶——绘制覆盖物

所有叠加或覆盖到地图的内容,我们统称为地图覆盖物。如标注、矢量图形元素(包括:折线和多边形和圆)、定位图标等。覆盖物拥有自己的地理坐标,当您拖动或缩放地图时,它们会相应的处理。
覆盖物包括:本地覆盖物和搜索覆盖物
本地覆盖物的抽象基类:OverlayOptions(核心类)
圆形覆盖物: CircleOptions
文字覆盖物: TextOptions
marker覆盖物: MarkerOptions
圆点覆盖物:DotOptions
ground 覆盖物:GroundOverlayOptions
圆点覆盖物:DotOptions
多边形覆盖物:PolygonOptions
折线覆盖物:PolylineOptions
弧线覆盖物:ArcOptions

1.绘制圆

既然熟悉了这些基础的知识,那我们就先来绘制一个圆吧

写一个drawCircle()方法让onCreate()调用

// 绘制圆
private void drawCircle() {
    // 1.创建自己
    CircleOptions circleOptions = new CircleOptions();
    // 2.设置数据 以世界之窗为圆心,1000米为半径绘制
    circleOptions.center(new LatLng(22.5422870000, 113.9804440000))//中心
    .radius(1000)  //半径
    .fillColor(0x60FF0000)//填充圆的颜色
    .stroke(new Stroke(10, 0x600FF000));  //边框的宽度和颜色
    //把绘制的圆添加到百度地图上去
     mBaiduMap.addOverlay(circleOptions);
    }

说了这么多,还是没有看图来的实在,我们来看下截图

circle

2.绘制文字

同样的我们在写一个方法drawText();
// 绘制文字
private void drawText() {
    TextOptions textOptions = new TextOptions();
    textOptions.fontColor(Color.RED) //设置字体颜色
    .text("自定义文字覆盖物")  //设置显示文本
    .position(new LatLng(22.5422870000, 113.9804440000))   //设置显示坐标
    .fontSize(20) //设置文本大小
    .typeface(Typeface.SERIF)  //设置字体 Android的字体就三种,对称的,不对称的,等宽的
    .rotate(30);  //设置旋转角度
    //把绘制的圆添加到百度地图上去
    mBaiduMap.addOverlay(textOptions);
    }

截图

text

3.绘制Mark覆盖物

Mark覆盖物就有趣多了,她是可以让我们自定义一张图片放上去的,就像那些打车软件一样可以让地图上看到一些车辆的信息
同样的,不管三七二十一,我们继续写一个方法drawMark();
先看看我这张要塞进去的图片

logo

// 绘制mark覆盖物
    private void drawMark() {
        MarkerOptions markerOptions = new MarkerOptions();
        BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.logo); // 描述图片
        markerOptions.position(new LatLng(22.5422870000, 113.9804440000)) // 设置位置
                .icon(bitmap) // 加载图片
                .draggable(true) // 支持拖拽
                .title("世界之窗旁边的草房"); // 显示文本
        //把绘制的圆添加到百度地图上去
        mBaiduMap.addOverlay(markerOptions);
    }

截图

mark

设置Mark覆盖物点击出现泡泡效果

不多说啥,先上个图给大家看看效果

pop
实现这样的一个效果,其实就是加了一个pop
我们首先得自己定义一个activity_pop.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingBottom="0dip" >

    <LinearLayout
        android:id="@+id/user_info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dip"
        android:layout_weight="1"
        android:background="@drawable/popupmap"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/round"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="2dip"
            android:src="@drawable/round" />

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:text="标题"
            android:textSize="20sp" />

        <ImageView
            android:id="@+id/roads"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/roads" />
    </LinearLayout>

</LinearLayout>

预览是这样子的
预览
首先,我们得初始化一些变量

//要显示的pop
private View pop;
//pop中的文本信息
private TextView title;

pop的初始化

//初始化pop
private void initPop() {
        pop = View.inflate(getApplicationContext(), R.layout.activity_pop, null);
        //必须使用百度的params
        LayoutParams params = new MapViewLayoutParams.Builder().layoutMode(MapViewLayoutParams.ELayoutMode.mapMode) //按照经纬度设置
                .position(new LatLng(22.5422870000, 113.9804440000)) //这个坐标无所谓的,但是不能传null
                .width(MapViewLayoutParams.WRAP_CONTENT)  //宽度
                .height(MapViewLayoutParams.WRAP_CONTENT)  //高度
                .build();
        mMapView.addView(pop,params);
        //先设置隐藏,点击的时候显示
        pop.setVisibility(View.INVISIBLE);
        //初始化这个title
        title = (TextView) pop.findViewById(R.id.title);
    }

mark的点击事件

/**mark的点击事件
* 点击某一个mark在他上放显示泡泡
 * 加载pop 添加到mapview 把他设置为隐藏 当点击的时候更新pop的位置 设置为显示
 */
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {

            @Override
            public boolean onMarkerClick(Marker result) {
                //处理点击 ,当点击的时候更新并且显示位置
                LayoutParams params = new MapViewLayoutParams.Builder().
                        layoutMode(MapViewLayoutParams.ELayoutMode.mapMode) //按照经纬度设置位置
                        .position(result.getPosition()) //这个坐标无所谓的,但是不能传null
                        .width(MapViewLayoutParams.WRAP_CONTENT)  //宽度
                        .height(MapViewLayoutParams.WRAP_CONTENT)  //高度
                        .yOffset(-5)  //相距  正值往下  负值往上
                        .build();
                mMapView.updateViewLayout(pop, params);
                pop.setVisibility(View.VISIBLE);
                //更新下title
                title.setText(result.getTitle());
                return true;
            }
        });
这边新加一个功能,就是泡泡轮播切换,咱先看效果图:

这里写图片描述
其实实现这个不难,就是在设置icon的时候设置一个icons穿进去一个Bitmap的list

//拿上面那个方法直接改的设置icon
// 绘制mark覆盖物
private void drawMark() {
        MarkerOptions markerOptions = new MarkerOptions();
        BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.logo); // 描述图片
        ArrayList<BitmapDescriptor> bitmaps = new ArrayList<BitmapDescriptor>();
        bitmaps.add(bitmap);  //显示多个图片的来回切换,类似于帧动画
        bitmaps.add(BitmapDescriptorFactory.fromResource(R.drawable.icon_geo));
        markerOptions.position(new LatLng(22.5422870000, 113.9804440000)) // 设置位置
                //.icon(bitmap) // 加载图片
                //切换图片
                .icons(bitmaps)
                .period(10) //切换时间
                .draggable(true) // 支持拖拽
                .title("世界之窗旁边的草房"); // 显示文本
        mBaiduMap.addOverlay(markerOptions);
    }

好的,Mark覆盖物写得差不多了 ,继续往下看吧

七.地图高阶——搜索路线标记

真不好意思,最近一直在加班,空闲的时间越来越少,没事,记录撸代码!!!
接下来讲的是路线标记,相信不少人应该知道,地图导航的时候会帮你标记一条路线,我们今天就来实现这个功能,后续有哪些方法有疏漏,也希望博友能指点出来,毕竟我也是技术渣渣
百度地图移动版API集成搜索服务包括:
位置检索、周边检索、范围检索、公交检索、驾乘检索、步行检索
核心类: PoiSearch和OnGetPoiSearchResultListener
               RoutePlanSearch和OnGetRoutePlanResultListener
实现思路
初始化PoiSearch类,通过setOnGetPoiSearchResultListener方法注册搜索结果的监听对象OnGetPoiSearchResultListener ,实现异步搜索服务。
通过自定义MySearchListener实现类,处理不同的回调方法,获得搜索结果。
注意, OnGetPoiSearchResultListener只支持一个,以最后一次设置为准
结合覆盖物展示搜索
本地搜索覆盖物:PoiOverlay
驾车路线覆盖物:DrivingRouteOverlay
步行路线覆盖物:WalkingRouteOverlay
换乘路线覆盖物:TransitOverlay

1.范围搜索,PoiOverlay的点击事件(矩形)

我们直接写一个search()方法让onCreate()调用吧
直接撸代码,实现search();
// 范围搜索
    private void search() {
        // 实例化搜索方法
        PoiSearch newInstance = PoiSearch.newInstance();
        newInstance.setOnGetPoiSearchResultListener(new SearchListener());
        // 发出搜索的请求 范围检索
        PoiBoundSearchOption boundOption = new PoiBoundSearchOption();
        LatLngBounds latLngBounds = new LatLngBounds.Builder() // 确定两点坐标(东北,西南)
                // 这里我们随机弄两个坐标 分别是深圳世界之窗附近
                .include(new LatLng(22.5441560000, 113.9828800000)) // 世界之窗右上角的美加广场
                .include(new LatLng(22.5413850000, 113.9777770000)) // 世界之窗左下角的一个不知道叫啥的街道
                .build();
        boundOption.bound(latLngBounds); // 设置搜索的范围
        boundOption.keyword("世界之窗"); // 搜索的关键字
        newInstance.searchInBound(boundOption);
    }
实现它的Listener
class SearchListener implements OnGetPoiSearchResultListener {

        @Override
        public void onGetPoiDetailResult(PoiDetailResult result) {

        }

        @Override
        public void onGetPoiResult(PoiResult result) {
            // 收到发送过来的搜索请求之后我们进行处理
            if(result == null || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error){
                Toast.makeText(getApplicationContext(), "未搜索到结果", Toast.LENGTH_LONG).show();
                return;
            }
            //搜索类型的类
            PoiOverlay overlay = PoiOverlay(mBaiduMap);  //处理搜索Poi的覆盖物
            mBaiduMap.setOnMarkerClickListener(overlay);// 把事件分发给overlay,overlay才能处理点击事件
            overlay.setData(result);  //设置结果
            overlay.addToMap;//把搜索的结果添加到地图中去
            overlay.zoomToSpan(); //自动缩放到所以的mark覆盖物都能看到
        }
    }
自己实现它的点击事件
//自己实现点击事件
    class MyPoiOverlay extends PoiOverlay {

        public MyPoiOverlay(BaiduMap arg0) {
            super(arg0);
        }

        @Override
        public boolean onPoiClick(int index) {
            PoiResult poiResult = getPoiResult();
            PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到点击的那个poi信息
            String text = poiInfo.name + "," + poiInfo.address;
            Toast.makeText(getApplicationContext(), text, 0).show();
            return super.onPoiClick(index);
        }

    }
官方的效果,点击后Toast

这里写图片描述

2.周边搜索(圆形)

周边搜索和范围搜索基本一致,我就直接上代码了
private void search() {
        poiSearch = PoiSearch.newInstance();
        poiSearch.setOnGetPoiSearchResultListener(new MyListener());

        PoiNearbySearchOption nearbyOption = new PoiNearbySearchOption();
        nearbyOption.location(hmPos);// 设置中心点
        nearbyOption.radius(1000);// 设置半径 单位是米
        nearbyOption.keyword("加油站");// 关键字
        poiSearch.searchNearby(nearbyOption);
    }

    class MyListener implements OnGetPoiSearchResultListener{

        @Override
        public void onGetPoiDetailResult(PoiDetailResult result) {
            if(result==null||SearchResult.ERRORNO.RESULT_NOT_FOUND==result.error){
                Toast.makeText(getApplicationContext(), "未搜索到结果", 0).show();
                return;
            }

            String text = result.getAddress()+ "::" + result.getCommentNum() + result.getEnvironmentRating();
            Toast.makeText(getApplicationContext(), text, 0).show();
        }

        @Override
        public void onGetPoiResult(PoiResult result) {
            if(result==null||SearchResult.ERRORNO.RESULT_NOT_FOUND==result.error){
                Toast.makeText(getApplicationContext(), "未搜索到结果", 0).show();
                return;
            }
            PoiOverlay overlay = new MyPoiOverlay(baiduMap);// 搜索poi的覆盖物
            baiduMap.setOnMarkerClickListener(overlay);// 把事件分发给overlay,overlay才能处理点击事件
            overlay.setData(result);// 设置结果
            overlay.addToMap();// 把搜索的结果添加到地图中
            overlay.zoomToSpan();// 缩放地图,使所有Overlay都在合适的视野内 注: 该方法只对Marker类型的overlay有效
        }

    }
    class MyPoiOverlay extends PoiOverlay {

        public MyPoiOverlay(BaiduMap arg0) {
            super(arg0);
        }

        @Override
        public boolean onPoiClick(int index) {
            PoiResult poiResult = getPoiResult();
            PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到点击的那个poi信息
            String text = poiInfo.name + "," + poiInfo.address;
            Toast.makeText(getApplicationContext(), text, 0).show();

            PoiDetailSearchOption detailOption = new PoiDetailSearchOption();
            detailOption.poiUid(poiInfo.uid);// 设置poi的uid
            poiSearch.searchPoiDetail(detailOption);
            return super.onPoiClick(index);
        }

    }

3.城市内搜索

基本上是一摸一样的
private PoiSearch poiSearch;
private int currentPageIndex = 0;
private void search() {
        poiSearch = PoiSearch.newInstance();
        poiSearch.setOnGetPoiSearchResultListener(new MyListener());
        search();
        PoiCitySearchOption cityOption = new PoiCitySearchOption();
        cityOption.city("北京");
        cityOption.keyword("加油站");
        cityOption.pageNum(currentPageIndex);
        poiSearch.searchInCity(cityOption);
    }

    class MyListener implements OnGetPoiSearchResultListener {

        @Override
        public void onGetPoiDetailResult(PoiDetailResult result) {

        }

        @Override
        public void onGetPoiResult(PoiResult result) {
            if (result == null
                    || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error) {
                Toast.makeText(getApplicationContext(), "未搜索到结果", 0).show();
                return;
            }
            String text = "共" + result.getTotalPageNum() + "页,共"
                    + result.getTotalPoiNum() + "条,当前第"
                    + result.getCurrentPageNum() + "页,当前页"
                    + result.getCurrentPageCapacity() + "条";

            Toast.makeText(getApplicationContext(), text, 1).show();
            baiduMap.clear();// 清空地图所有的 Overlay 覆盖物以及 InfoWindow
            PoiOverlay overlay = new MyPoiOverlay(baiduMap);// 搜索poi的覆盖物
            baiduMap.setOnMarkerClickListener(overlay);// 把事件分发给overlay,overlay才能处理点击事件
            overlay.setData(result);// 设置结果

            overlay.addToMap();// 把搜索的结果添加到地图中
            overlay.zoomToSpan();// 缩放地图,使所有Overlay都在合适的视野内 注:
                                    // 该方法只对Marker类型的overlay有效
        }

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_1){
            currentPageIndex++;
            search();
        }
        return super.onKeyDown(keyCode, event);
    }

    class MyPoiOverlay extends PoiOverlay {

        public MyPoiOverlay(BaiduMap arg0) {
            super(arg0);
        }

        @Override
        public boolean onPoiClick(int index) {
            PoiResult poiResult = getPoiResult();
            PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到点击的那个poi信息
            String text = poiInfo.name + "," + poiInfo.address;
            Toast.makeText(getApplicationContext(), text, 0).show();
            return super.onPoiClick(index);
        }

    }

这里写图片描述

4.路线检索(驾车路线)

//驾车路线
    private void driving(){
        RoutePlanSearch newInstance = RoutePlanSearch.newInstance();
        newInstance.setOnGetRoutePlanResultListener(new MyListener());

        //驾车路线
        DrivingRoutePlanOption drivingOption = new DrivingRoutePlanOption();
        PlanNode from = PlanNode.withLocation(new LatLng(22.5422870000, 113.9804440000));  //设置起点世界之窗
        PlanNode to = PlanNode.withLocation(new LatLng(22.5455910000,113.9880900000));  //设置终点就附近的欢乐谷
        drivingOption.from(from);
        drivingOption.to(to);
        drivingOption.policy(DrivingRoutePlanOption.DrivingPolicy.ECAR_DIS_FIRST); //方案:最短距离 这个自己设置 比如时间短之类的
        newInstance.drivingSearch(drivingOption);
    }
    class MyListener implements OnGetRoutePlanResultListener{

        @Override
        public void onGetDrivingRouteResult(DrivingRouteResult result) {
            //驾车
            if(result == null || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error){
                Toast.makeText(getApplicationContext(), "未搜索到结果", Toast.LENGTH_LONG).show();
                return;
            }
            //开始处理结果了
            DrivingRouteOverlay overlay = new MyDrivingOverlay(baiduMap);
            baiduMap.setOnMarkerClickListener(overlay);// 把事件传递给overlay
            overlay.setData(result.getRouteLines().get(0));// 设置线路为第一条
            overlay.addToMap();
            overlay.zoomToSpan();
        }

        @Override
        public void onGetTransitRouteResult(TransitRouteResult result) {
            // 公交换乘

        }

        @Override
        public void onGetWalkingRouteResult(WalkingRouteResult result) {
            // 步行

        }

    }
    class MyDrivingOverlay extends DrivingRouteOverlay{

        public MyDrivingOverlay(BaiduMap arg0) {
            super(arg0);
        }

        @Override
        public BitmapDescriptor getStartMarker() {
            //覆写此方法以改变默认起点图标
            return BitmapDescriptorFactory.fromResource(R.drawable.icon_st);
        }
        @Override
        public BitmapDescriptor getTerminalMarker() {
            //覆写此方法以改变默认终点图标
            return BitmapDescriptorFactory.fromResource(R.drawable.icon_en);
        }

    }
官方的效果图

这里写图片描述

5.6.公交换乘和步行路线,其实和驾车路线的写法是一样的这里就不写了

写的时候不知道为什么我的Overlay类来是创建不出来,所以代码拙劣的地方还请海涵

八.地图高阶——定位系统

这个相信是大家经常用到的
LocationClient和BDLocationListener
首先需要打开定位图层BaiduMap.setMyLocationEnabled(true);
设置监听器LocationClient. registerLocationListener(BDLocationListener)
设置定位模式baiduMap. setLocationMode(LocationMode)
Hight_Accuracy,高精度定位模式:这种定位模式下,会同时使用网络定位和GPS定位,优先返回最高精度的定位结果;
Battery_Saving,低功耗定位模式:这种定位模式下,不会使用GPS,只会使用网络定位(Wi-Fi和基站定位)
Device_Sensors,仅用设备定位模式:这种定位模式下,不需要连接网络,只使用GPS进行定位,这种模式下不支持室内环境的定位
设置定位显示模式BaiduMap.setMyLocationConfigeration(MyLocationConfiguration)
定位数据获取:在BDLocationListener. onReceiveLocation(BDLocation result)方法中设置定位数据,
baiduMap.setMyLocationData(MyLocationData);
一个GPS定位,不过必须要三颗星以上才可定位,不然是定不了的,还有一个基站地位,他其实每个基站都有一个ID,就是一个位置,查到最近基站的位置然后去服务器里请求返回位置信息,还有一个wifi定位,当你的手机连接wifi,你开始定位的时候,把wifi的地址发送到百度的服务器,服务器会把大部分wifi地址都有收录,直接返回经纬度

地址:http://developer.baidu.com/map/index.php?title=android-locsdk/guide/v5-0

我们根据百度提供的文档去做

1.在application标签中声明service组件,每个app拥有自己单独的定位service

<service android:name="com.baidu.location.f" 
android:enabled="true" 
 //跑在一个新的进程中
android:process=":remote"> 
</service>
主要用到的两个类
public LocationClient mLocationClient;
public BDLocationListener myListener;
private BitmapDescriptor geo;
然后我们直接写个方法lacate();

    private void lacate() {
        mLocationClient = new LocationClient(getApplicationContext());
        myListener = new MyListener();
        mLocationClient.registerLocationListener(myListener);
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationMode.Hight_Accuracy);// 设置定位模式
        option.setCoorType("bd09ll");// 返回的定位结果是百度经纬度,默认值gcj02
        option.setScanSpan(5000);// 设置发起定位请求的间隔时间为5000ms
        option.setIsNeedAddress(true);// 返回的定位结果包含地址信息
        option.setNeedDeviceDirect(true);// 返回的定位结果包含手机机头的方向
        mLocationClient.setLocOption(option);
        geo = BitmapDescriptorFactory
                .fromResource(R.drawable.icon_geo);
        MyLocationConfiguration configuration = new MyLocationConfiguration(
                MyLocationConfiguration.LocationMode.FOLLOWING, true, geo);
        baiduMap.setMyLocationConfigeration(configuration);// 设置定位显示的模式
        baiduMap.setMyLocationEnabled(true);// 打开定位图层
    }
继续自己写个Listener
class MyListener implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation result) {
            if (result != null) {
                MyLocationData data = new MyLocationData.Builder()
                        .latitude(result.getLatitude())
                        .longitude(result.getLongitude()).build();
                baiduMap.setMyLocationData(data);
            }
        }

    }
我们可以模拟一下使用各种方式去定位
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_1:
            // 正常
            baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
                    MyLocationConfiguration.LocationMode.NORMAL, true, geo));// 设置定位显示的模式
            break;
        case KeyEvent.KEYCODE_2:
            // 罗盘
            baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
                    MyLocationConfiguration.LocationMode.COMPASS, true, geo));// 设置定位显示的模式
            break;
        case KeyEvent.KEYCODE_3:
            // 跟随
            baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
                    MyLocationConfiguration.LocationMode.FOLLOWING, true, geo));// 设置定位显示的模式
            break;

        default:
            break;
        }
        return super.onKeyDown(keyCode, event);
    }

百度地图算是写完一半了,为什么说只写完了一半,因为时间紧迫,里面肯定会有些错误的编写,不过思想是对的,你按照步骤来,结合你对百度API的认知,这些其实都是很简单就去实现的,这里只是作为一个抛砖引玉

后续还会持续修订更改,如有错误,欢迎点评,谢谢了!

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9379582

目录
相关文章
|
3月前
|
安全 开发工具 Android开发
几个Flutter常见诊断错误与解决Android toolchain - develop for Android devices X Unable to locate Android SDK
几个Flutter常见诊断错误与解决Android toolchain - develop for Android devices X Unable to locate Android SDK
248 0
|
6月前
|
API 开发工具 Android开发
解决 Android App 上架 Google play后 ,签名变更,第三方sdk无法登录
解决 Android App 上架 Google play后 ,签名变更,第三方sdk无法登录
146 0
|
7月前
|
编解码 Android开发 数据安全/隐私保护
Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
好多开发者可能疑惑,外部数据实时预览播放,到底有什么用? 是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.264/H.265数据,除了想转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至对数据做二次处理(视频分析、实时水印字符叠加等,然后二次编码),基于这样的场景诉求,我们开发了Android平台外部编码数据实时预览播放模块。
|
7月前
|
编解码 Android开发
Android native层实现MediaCodec编码H264/HEVC
Android平台在上层实现mediacodec的编码,资料泛滥,已经不再是难事,今天给大家介绍下,如何在Android native层实现MediaCodec编码H264/HEVC,网上千篇一律的接口说明,这里不再赘述,本文主要介绍下,一些需要注意的点,权当抛砖引玉,相关设计界面如下:
131 0
|
21天前
|
Java Android开发
Android Studio的使用导入第三方Jar包
Android Studio的使用导入第三方Jar包
10 1
|
3月前
|
开发工具 Android开发
Android获取SDK的版本信息
Android获取SDK的版本信息
39 0
|
4月前
|
安全 Java Android开发
Android App开发之安全加固中反编译、代码混淆、第三方加固以及重签名的讲解及实战(图文解释 简单易懂)
Android App开发之安全加固中反编译、代码混淆、第三方加固以及重签名的讲解及实战(图文解释 简单易懂)
70 0
|
4月前
|
监控 Java 开发工具
基于Eclipse+SDK+ADT+DDMS的安卓开发环境完整搭建过程
基于Eclipse+SDK+ADT+DDMS的安卓开发环境完整搭建过程
45 0
基于Eclipse+SDK+ADT+DDMS的安卓开发环境完整搭建过程
|
6月前
|
数据安全/隐私保护 Android开发 iOS开发
解决第三方邮箱APP登陆QQ、163邮箱无法验证账户名或密码的问题(IOS、MacOS、Windows、Android)
解决第三方邮箱APP登陆QQ、163邮箱无法验证账户名或密码的问题(IOS、MacOS、Windows、Android)
109 0
|
7月前
|
数据采集 编解码 数据处理
Android平台如何高效率实现GB28181对接?
GB28181协议是一种用于设备状态信息报送的协议,可以在不同设备之间进行通信和数据传输。