参考:
Android Studio 百度地图开发:http://blog.csdn.net/u012005313/article/details/48580229
陆陆续续接触了百度地图的开发,官网上的资料以及 sample
都还比较详细,不过内容较多,也比较复杂,并不是全部的功能都有讲解,所以每次重新接触都需要花费一段时间学习。这次,将关于百度地图 sdk
开发的步骤记录下来,方便下次使用
主要内容
地图开发浅析
不同的地图采用不同的坐标系,手机使用的 GPS
全球卫星定位系统采用 WGS84
坐标系,百度地图采用坐标系为 BD09
百度地图坐标查找系统:百度地图 拾取坐标系统
Note:百度地图坐标查找系统查找到的坐标属于 BD09
坐标系,不同坐标系之间的坐标需要经过转换才能正确使用
申请密匙
使用百度地图 sdk
之前需要申请开发密匙,密匙申请地址:
http://lbsyun.baidu.com/apiconsole/key
申请百度地图 Android SDK
密匙的官网教程:
申请密钥Android SDK
里面的讲解很详细,这里记录下如何获取 Android
签名证书的 SHA1 值:
打开控制台窗口,进入
.android
目录(当前开发环境为win7
,.android
文件夹在c:\Users\Lenovo\
中)输入命令
keytool -list -v -keystore debug.keystore
输入密匙口令(默认为
android
),即在窗口中打印出SHA1
码:如果想要把打印出的值放入文本中,方便操作,可以使用下面的命令
keytool -list -v -keystore debug.keystore > sha1.txt
在当前目录下找到
sha1.txt
,打开可以找到SHA1
值
编译官方 demo
demo
就像上面说的,使用百度地图 sdk
必须申请密匙,编译百度提供的 Demo
的时候,就遇到了关于开发密匙的问题
下载,打开 demo
工程,发现并没有开发密匙,那就按照上面的教程找到 SHA1
值和包名,申请得到开发密匙后,编译运行,发现 key验证错误
在网上找到解决方法:
百度地图Key验证失败230错误
其实是自己没有仔细查找,依葫芦画瓢就使用了 keytool
命令,百度官方 demo
已经包含了 debug.keystore
,所以不需要使用本地默认的 debug.keystore
,使用 demo
里包含的 debug.keystore
即可
Note:在日志中,百度地图也给了解决方法链接:http://bbs.lbsyun.baidu.com/forum.php?mod=viewthread&tid=106461
Hello BaiduMap
的实现
Hello BaiduMap
的实现
官网文档有一个关于如何使用 sdk
,以及如何使用百度地图控件实现一个最简单的地图显示的教程,里面有基于 eclipse
和 android studio
的配置,我使用的是 android studio
,所以接下来使用 android studio
构建一个百度地图的 BaiduMap Demo
- 下载
sdk
百度地图 Android sdk
下载地址:
相关下载Android地图SDK
Note:实际开发过程中,可结合需求下载,以减小 sdk
大小
- 配置
sdk
新建 Android Studio
工程,将解压后的 sdk
中的 .jar
文件放入 app -> libs
文件夹中,对每个jar文件,右键-选择 Add As Library
,导入到工程中。在 app -> src -> main
路径下新建文件夹 jniLibs
,将 .so
文件放入其中
Note:.so
文件可能会按不同 CPU
架构分类,将整个文件夹放入 jniLibs
我选择了全部功能的 sdk
包,可实现功能如下:
Note:下载解压后发现还包含了一个 assets
文件夹,可以将这个放入 app -> main
路径下
- 配置开发密匙
获取 SHA1
值和包名,申请开发密匙
在 app -> src -> AndroidMaifest.xml
中,加入:
<application>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="开发者 key" />
</application>
value
部分替换为开发密匙
- 配置使用权限
在 app -> src -> AndroidManifest.xml
中,加入:
<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" />
- 初始化
sdk
在初始化地图组件前初始化地图 sdk
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
//注意该方法要再setContentView方法之前实现
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
}
由于需要在多个 activity
中使用地图,所以将初始化方法放在 Application
中进行,新建文件夹 App
,继承自 Application
:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
SDKInitializer.initialize(getApplicationContext());
}
}
修改 AndroidManifest.xml
中的 Application
为自定义的 App
:
<application
...
android:name=".App"
...
...>
</application>
- 使用地图控件
地图控件为 MapView
,在 xml
文件中加入:
<com.baidu.mapapi.map.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
在使用地图控件过程中,需要显式设置生命周期管理,修改如下:
public class HelloActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello);
mapView = (MapView) findViewById(R.id.map_view);
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
编译,安装,运行,成功:
地图类型与缩放级别
地图类型
百度地图 Android SDK
提供了 3
种类型的地图资源:普通矢量地图、卫星图和空白地图
从地图控件 MapView
中获取地图 BaiduMap
:
BaiduMap baiduMap = mapView.getMap();
设置地图类型 setMapType
:
//普通地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
//卫星地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
//空白地图, 基础地图瓦片将不会被渲染。在地图类型中设置为NONE,将不会使用流量下载基础地图瓦片图层。使用场景:与瓦片图层一起使用,节省流量,提升自定义瓦片图下载速度。
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NONE);
通过 mBaiduMap.getMapType
获取地图当前类型
实时交通图 和 城市热力图
没有用到过,不过在官网教程上有介绍,记录一下
和设置地图类型类似,获取 BaiduMap
后
开启交通图:
//开启交通图
mBaiduMap.setTrafficEnabled(true);
开启热力图:
//开启热力图
mBaiduMap.setBaiduHeatMapEnabled(true);
- 实时交通图和城市热力图的设置与地图类型无关,就是哪种地图类型都可以开启这两种类型
- 实时交通图和城市热力图并不互斥,可以同时开启
通过函数 mBaiduMap.isSupportBaiduHeatMap
查询当前图区是否支持百度热力图
通过函数 mBaiduMap.setTrafficEnabled
查询是否已打开交通图
缩放级别
百度地图缩放级别为 3 - 21
级,级数越高,精度越高
V3.7.0起,地图支持缩放至21级缩放显示;卫星图、热力图和交通路况图最高支持20级缩放显示。 在打开21级地图切换卫星图、热力图和交通路况图,地图层级会自动缩放到20级。
也就是说,现在开发的 Android
百度地图的使用缩放最高就是 21
级了,其中卫星图、热力图和交通路况图只能缩放到 20
级
查询最大最小缩放级别
获取 BaiduMap
后,可以查询最大最小缩放级别:
float maxZoom = baiduMap.getMaxZoomLevel();
float minZoom = baiduMap.getMinZoomLevel();
Log.e(TAG, "onCreate: minZoom = " + minZoom + " maxZoom = " + maxZoom);
打印出来是 [3 - 22]
:
onCreate: minZoom = 3.0 maxZoom = 22.0
Note:在实际使用中,真的只能缩放到 21
级,可以是百度没改好吧
查询当前缩放级别
刚开始加载地图,获取到 BaiduMap
后,可以获取 地图状态类 MapStatus
,其包含了当前缩放级别:
MapStatus mapStatus = baiduMap.getMapStatus();
currentZoom = mapStatus.zoom;
Log.e(TAG, "onCreate: currentZoom = " + currentZoom);
在实际运行过程中,可以通过 地图绘制回调接口 BaiduMap.OnMapDrawFrameCallback
获取当前缩放级别:
baiduMap.setOnMapDrawFrameCallback(new BaiduMap.OnMapDrawFrameCallback() {
@Override
public void onMapDrawFrame(GL10 gl10, MapStatus mapStatus) {
}
@Override
public void onMapDrawFrame(MapStatus mapStatus) {
currentZoom = mapStatus.zoom;
}
});
如果要使用当前缩放级别,可以在 地图渲染完成回调接口 BaiduMap.OnMapRenderCallback
中进行操作:
baiduMap.setOnMapRenderCallbadk(new BaiduMap.OnMapRenderCallback() {
@Override
public void onMapRenderFinished() {
Log.e(TAG, "onMapRenderFinished: currentZoom = " + currentZoom);
}
});
地图控制
百度地图除了显示地图信息外,还会显示地图 logo
、指南针以及比例尺,以及缩放控件
地图 logo
默认在左下角显示,不可删除
Logo
位置保存为一个枚举类 LogoPosition
:
package com.baidu.mapapi.map;
public enum LogoPosition {
logoPostionleftBottom,
logoPostionleftTop,
logoPostionCenterBottom,
logoPostionCenterTop,
logoPostionRightBottom,
logoPostionRightTop;
private LogoPosition() {
}
}
通过 mapView.getLogoPosition()
获取当前 Logo
位置
通过 mapView.setLogoPosition()
设置 Logo
位置
比例尺
通过 mapView.showScaleControl()
设置是否显示比例尺
通过 mapView.getMapLevel()
获取当前地图级别对应比例尺大小
通过 mapView.getScaleControlViewHeight()
获取比例尺高度
通过 mapView.getScaleControlViewWidth()
获取比例尺宽度
缩放控件
通过 mapView.showZoomControls()
设置是否显示缩放控件
通过上一节介绍的方法获取缩放级别
通过设置 baiduMap.setMaxAndMinZoomLevel
设置地图支持的最大最小缩放级别,取值范围为 [3, 21]
:
public final void setMaxAndMinZoomLevel(float max, float min)
设置地图最大以及最小缩放级别,地图支持的最大最小级别分别为[3-21]
参数:
max - [3-21] 且 max > min, 否则无效
min - [3-21] 且 max > min, 否则无效
地图手势
百度地图同样提供了多种手势操作,包括平移,缩放,俯视(3D
),旋转,是否设置指南针
首先获取地图控件 MapView
:
MapView mapView = (MapView) findViewById(R.id.map_view);
接着获取百度地图 BaiduMap
:
BaiduMap baiduMap = mapView.getMap();
最后获取百度地图 UI
控制器 UiSettings
:
UiSettings uiSettings = baiduMap.getUiSettings();
在百度地图 UI 控制器 UiSettings
中可以进行上述手势操作的查询与设置。
同时 UiSettings
在含有是否允许所有手势操作功能:
public void setAllGesturesEnabled(boolean enabled)
设置是否允许所有手势操作
参数:
enabled - 是否允许所有手势操作
标注覆盖物
可以在百度地图设定标注物
图像标注
利用图像进行标注
单个标注
假定标注浙江理工大学(坐标:120.359669,30.319648
)
首先获取
MapView
控件以及百度地图BaiduMap
:MapView mapView = (MapView) findViewById(R.id.map_view); BaiduMap baiduMap = mapView.getMap();
接下来改变地图状态,将地图中心转到浙江理工大学:
// 新建一个坐标点 LatLng latLng = new LatLng(30.319648, 120.359669); // 设置地图新中心点 MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng); // 改变地图状态 baiduMap.setMapStatus(mapStatusUpdate);
Note:也可以在设置地图新中心点的同时改变缩放级别,以便更清晰的查看结果,修改如下:
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(latLng, 16.0f); //MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng);
最后创建图像覆盖物并加载到地图上:
// 创建图标 BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_marker); // 创建覆盖物 OverlayOptions overlayOptions = new MarkerOptions() .position(latLng) .icon(bitmapDescriptor); // 向地图添加一个 Overlay baiduMap.addOverlay(overlayOptions);
Note:对于 BitmapDescriptor
而言,不再需要使用后,及时调用 recycle
函数,回收 bitmap
资源
多个标注
可以一次性载入多个图标,将创建的多个 MarkerOptions
整合为列表,调用函数 baiduMap.addOverlays()
载入即可:
// 120.359669,30.319648 浙江理工大学
// 120.359629,30.327168 杭州职业技术学院
// 120.356678,30.31653 杭州地铁文泽路
List<LatLng> latLngList = new ArrayList<>();
LatLng point1 = new LatLng(30.319648, 120.359669);
LatLng point2 = new LatLng(30.327168, 120.359629);
LatLng point3 = new LatLng(30.31653, 120.356678);
latLngList.add(point1);
latLngList.add(point2);
latLngList.add(point3);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_marker);
List<OverlayOptions> overlayOptionsList = new ArrayList<>();
for (LatLng latLng : latLngList) {
OverlayOptions overlayOptions = new MarkerOptions()
.position(latLng)
.icon(bitmapDescriptor);
overlayOptionsList.add(overlayOptions);
}
baiduMap.addOverlays(overlayOptionsList);
Note:清除单个 Marker
可以使用
Note:调用 BaiduMap.clear()
可以清空地图所有的 Overlay
覆盖物以及 InfoWindow
图像覆盖物额外功能
图像覆盖物 MarkerOptions
还可以设定标题,添加额外信息:
LatLng latLng = new LatLng(30.319648, 120.359669);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_marker);
Bundle bundle = new Bundle();
bundle.putString("extra", "Hello World");
OverlayOptions overlayOptions = new MarkerOptions()
.title("浙江理工大学")
.extraInfo(bundle)
.position(latLng)
.icon(bitmapDescriptor);
baiduMap.addOverlay(overlayOptions);
百度地图 BaiduMap
需要实现地图 Marker
覆盖物点击事件监听接口 BaiduMap.OnMarkerClickListener
,将该 Marker
的信息提取出来,包括标注坐标,标题,额外信息:
baiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
LatLng point = marker.getPosition();
Log.e(TAG, "onMarkerClick: " + point.toString());
String title = marker.getTitle();
Log.e(TAG, "onMarkerClick: title = " + title);
Bundle bundle = marker.getExtraInfo();
String extraInfo = bundle.getString("extra");
Log.e(TAG, "onMarkerClick: extra = " + extraInfo);
return false;
}
});
Note:可以设定 Marker
是否可显示
public boolean isVisible()
获取 marker 覆盖物的可见性
public MarkerOptions visible(boolean visible)
设置 marker 覆盖物的可见性
关于标注覆盖物拖拽
在百度地图 Android SDK
教程中说明标注覆盖物可拖拽,同时也设置了拖拽监听接口,不过我试了一下好像没有效果,等待日后解决
弹出窗覆盖物
有时希望在设置覆盖物的同时显示一些文字信息,比如该地点的名称等,可以使用百度地图提供了弹出窗覆盖物 InfoWindow
实现
InfoWindow
提供了两个构造器:
InfoWindow(BitmapDescriptor bd, LatLng position, int yOffset, InfoWindow.OnInfoWindowClickListener listener)
通过传入的 bitmap descriptor 构造一个 InfoWindow。
InfoWindow(View view, LatLng position, int yOffset)
通过传入的 view 构造一个 InfoWindow, 此时只是利用该view生成一个Bitmap绘制在地图中,监听事件由开发者实现。
Note:BitmapDescriptor
可以通过 BitmapDescriptorFactory.fromView(view)
得到
InfoWindow
同时包含一个信息窗口点击事件监听接口 InfoWindow.OnInfoWindowClickListener
,用于信息窗口点击事件处理,可在构造器中传入
如上面所示,在地图上标注浙江理工大学:
LatLng latLng = new LatLng(30.319648, 120.359669);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_marker);
Bundle bundle = new Bundle();
bundle.putString("extra", "Hello World");
OverlayOptions overlayOptions = new MarkerOptions()
.title("浙江理工大学")
.extraInfo(bundle)
.position(latLng)
.draggable(true)
.zIndex(16)
.icon(bitmapDescriptor);
baiduMap.addOverlay(overlayOptions);
addInfoWindow();
同时增加 InfoWindow
,显示浙江理工大学校名:
LatLng latLng = new LatLng(30.319648, 120.359669);
//创建InfoWindow展示的view
final Button button = new Button(getApplicationContext());
button.setText("浙江理工大学");
button.setBackgroundResource(R.drawable.popup);
InfoWindow.OnInfoWindowClickListener listener = new InfoWindow.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick() {
baiduMap.hideInfoWindow();
}
};
//创建InfoWindow , 传入 view, 地理坐标, y 轴偏移量
InfoWindow mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(button), latLng, -47, listener);
//显示InfoWindow
baiduMap.showInfoWindow(mInfoWindow);
实现效果:点击 InfoWindow
后消失
Note:可以在 Marker
的点击事件中设定 InfoWindow