上回我们学习了如何搭建一个google map应用,了解了基础知识,下面我们来深入学习google map中待发掘的宝藏
在这篇文章,我将告诉你
1. 如何创建google地图
2. Google地图 的模式,和地图类型
3. Google地图上的控件使用
4. Google地图的点击事件和其他事件
5. 摄像头移动知识
一. 地图对象
1. 获得地图对象
A. 地图控件所在的fragment
在上一篇中,我们自动生成项目后,可以看到MapActivity和它的布局文件activityt_maps,布局文件中直接使用fragment控件作为根节点,然后在activity中使用findFragmentById获得地图fragment。这里有两种获得方法
(1) 使用xml文件
(2) 使用代码获得
mMapFragment= MapFragment.newInstance();
FragmentTransaction fragmentTransaction =
getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.my_container, mMapFragment);
fragmentTransaction.commit();
注:Google Maps Android API 需要 API 级别 12 或更高级别,才能支持 MapFragment
对象。如果您的目标是低于 API级别 12 的应用,可通过
SupportMapFragment
(v4包的)
类访问同一功能。 您还必须提供 Android 支持库。
注:这里可以使用的碎片有SupportMapFragment和MapFragment,前者支持api12以前的机型,后者不是
B. 给fragment注册地图就绪的接口
地图碎片所在的activity界面需要实现 OnMapReadyCallback监听接口,并重写onMapReady方法,该方法返回的GoogleMap对象就是我们要的地图对象。MapFragment对象注册这个监听,mapFragment.getMapAsync(this);
注:必须从主线程调用 getMapAsync(),回调将在主线程中执行。 如果用户设备上未安装 Google Play 服务,则用户安装 Play 服务后才会触发回调。
使用地图对象时的关键类是GoogleMap类。 GoogleMap 在您的应用内为地图对象建模。 在您的 UI 内,地图将由 MapFragment对象或 MapView 对象表示。
GoogleMap自动处理下列操作:
- 连接到 Google 地图服务
- 下载地图图块。
- 在设备屏幕上显示图块。
- 显示如平移和缩放等各类控件。
- 通过移动和缩放地图响应平移和缩放手势
除了这些自动操作外,您还可以通过该 API 的对象和方法控制地图的行为。 例如,GoogleMap具有可响应地图上点击动作和触摸手势的回调方法。 您还可以利用向GoogleMap提供的对象在地图上设置标记图标以及为其添加叠层。
MapFragment
MapFragment是 Android
Fragment类的一个子类,用于在 AndroidFragment 中放置地图。 MapFragment对象充当地图容器,并提供对 GoogleMap 对象的访问权。
与 View 不同,Fragment 表示的是 Activity 中的一种行为或用户界面的某一部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。请参阅有关Fragment的
Android 文档,以了解更多信息。
MapView
MapView是 AndroidView类的一个子类,
用于在 Android View 中放置地图。 View 表示屏幕的某个矩形区域, 是 Android 应用和小工具的基本构建基块。 MapView 与 MapFragment 很相似,它也充当地图容器,通过 GoogleMap 对象公开核心地图功能。
在完全交互模式下使用该 API 时,此类的用户必须将所有Activity 生命周期方法都转发给 MapView类中的相应方法。 举例来说,生命周期方法包括 onCreate()、onDestroy()、onResume() 和 onPause()。 在精简模式下使用该 API 时,转发生命周期事件为可选操作。如需了解详情,请参阅精简模式文档。
2. 地图显示类型、
(1) 地图类型
获得地图对象之后你就可以设置地图的显示类型了
地图对象有如下显示类型:
Normal
典型道路地图。 显示道路、一些人造景观以及 河流等重要的自然景观。 此外,还会显示道路和 景观标签。
Hybrid
添加了道路地图的卫星照片数据。 此外,还会显示道路 和景观标签。
Satellite
卫星照片数据。 不显示道路和景观标签。
Terrain
地形数据。 地图包含颜色、轮廓线和标签以及 透视阴影。 此外,还会显示一些道路和标签。
None
无图块。 地图将渲染为空网格,不加载任何图块。
设置方法,调用 GoogleMap
对象的 setMapType()
方法,传递 GoogleMap
中定义的其中一个类型常量。
GoogleMap map;
.....
map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
(2) 室内地图
如果地图对象的显示类型为none和satellite,那么将会在用户放大地图时显示室内地图,在用户缩小时自动隐藏。
下面概要列出了 API 中的室内地图功能:
您可以通过调用GoogleMap.setIndoorEnabled(false) 禁用室内地图。默认情况下,室内地图处于启用状态。 室内地图一次只能显示在一幅地图上。默认情况下,这是向您的应用添加的第一幅地图。 如果您想在其他地图上显示室内地图, 请在第一幅地图上禁用它们,然后在第二幅地图上调用setIndoorEnabled(true)。
如需禁用默认层级选取器(楼层选取器),请调用 GoogleMap.getUiSettings().setIndoorLevelPickerEnabled(false)。 如需了解更多详情,请参阅与地图交互。
GoogleMap 上的一个接口OnIndoorStateChangeListener
允许您设置在一栋新建筑获得焦点或者激活建筑内的新楼层时调用的侦听器。如需了解更多详情,请参阅与地图交互。
GoogleMap.getFocusedBuilding() 为您获取当前获得焦点的建筑。您随后可以通过调用IndoorBuilding.getActiveLevelIndex()
找到当前激活的楼层。请参阅参考文档, 以了解 IndoorBuilding 对象和 IndoorLevel 对象中提供的所有信息。
添加平面图
选择位置 中提供了室内地图(平面图)。如果您想在应用中突出显示的建筑没有平面图数据,您可以:
直接向 Google 地图添加平面图。这样做可以将您的平面图提供给 Google 地图的所有用户。
将平面图以底面叠层 或 图块叠层 形式显示在您的地图上。 这样一来,只有您的应用的用户才能查看平面图。
3. 配置初始状态
意思就是配置地图初次加载出来的属性,有以下几点:
- 摄像头位置,包括:位置、缩放比例、方位和倾斜角度。 请参阅更改地图视图,了解有关摄像头定位的更多详情。
- 地图类型
- 缩放按钮和/或指南针是否出现在屏幕上
- 用户在操纵摄像头时可使用的手势
- 是否启用了精简模式。 精简模式地图是指地图的一种位图图像, 它支持完整 API 提供的一部分功能。
有两种方式来配置地图的初始化属性,一是xml,二是代码,和MapFragment的创建类似,也是这两种。
(1) 配置xml文件
A. 添加自定义属性命名空间
Maps API 为 MapFragment 或MapView 定义了一组自定义 XML 属性,
xmlns:map="http://schemas.android.com/apk/res-auto"
map是命名空间,可以自定义取名,注意现在引用自定义属性AS并不是使用包名了,是res-auto
B. 可用的属性
mapType
。 它用于指定要显示的地图类型。 有效 值包括none
、normal
、hybrid
、satellite
和
terrain
。cameraTargetLat
、cameraTargetLng
、cameraZoom
、cameraBearing
、
cameraTilt
。 它们用于指定摄像头的初始位置。uiZoomControls
、uiCompass
。 它们用于指定您是否希望将缩放控件和指南针出现在地图上。uiZoomGestures
、uiScrollGestures
、uiRotateGestures
、uiTiltGestures
。 它们用于指定在与地图交互时启用/禁用的手势。zOrderOnTop
。 控制地图视图的表面是否覆盖在其窗口上。请注意,如果指定此属性,将会覆盖所有其他可能出现在地图上的视图(例如缩放控件、my location 按钮)。useViewLifecycle
。 只对MapFragment
有效。 此属性指定是否应将地图的生命周期与 Fragment 的视图或 Fragment 本身关联。liteMode
。 值true
会将地图设置为精简模式。 精简模式地图是指地图的一种位图图像,它支持完整 API 提供的一部分功能。 该属性的默认值 为
false
。
Xml代码例子如下
<fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:map="http://schemas.android.com/apk/res-auto" android:name="com.google.android.gms.maps.MapFragment" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" map:cameraBearing="112.5" map:cameraTargetLat="-33.796923" map:cameraTargetLng="150.922433" map:cameraTilt="30" map:cameraZoom="13" map:mapType="normal" map:uiCompass="false" map:uiRotateGestures="true" map:uiScrollGestures="false" map:uiTiltGestures="true" map:uiZoomControls="false" map:uiZoomGestures="true"/>
注:如果您使用的是 Google Maps Mobile SDK for Work(是专为移动端定制的),则必须为每个属性添加 m4b_
前缀。例如,在指定地图类型属性时,请使用
m4b_mapType
而非 mapType
。 或者,在指定缩放控件时使用 m4b_uiZoomControls
而非
uiZoomControls
,依此类推。
(1) 代码方式
首先你需要创建GoogleMapOptions对象
GoogleMapOptionsgmo = new GoogleMapOptions();
然后通过该对象设置属性,可设置的属性和xml文件的相同,例如
gmo.mapType(GoogleMap.MAP_TYPE_SATELLITE)
.compassEnabled(false)
.rotateGesturesEnabled(false)
.tiltGesturesEnabled(false);
然后在你获取MapFragment或者MapView实例时在getInstance()的括号中传入GoogleMapOptions对象。
- 如果您使用的是 MapFragment,请使用 MapFragment.newInstance(GoogleMapOptions options) 静态出厂方法构建 Fragment 并传入您的自定义配置选项
- 如果您使用的是 MapView,请使用 MapView(Context, GoogleMapOptions) 构造函数并传入您的自定义配置选项
4. 地图内边距
第一次看这个还有点没看懂,多看了几遍才懂了,
GoogleMap.setPadding(left,top,right,bottom),设置内部区域的padding值,设置这个不会影响地图的显示,地图仍然充满整个屏幕,那我就纳闷儿,到底是干啥用的,为啥需要内边距,后来我知道了,由于google地图自带一些空间在屏幕边缘,还有他的公司徽标,我们需要设置内边距来让我们自己的控件不与之重合(他的控件在内部区域,我们的在padding设置的距离之间),重合了小心它告你侵权。
二. 精简模式
1. 设置精简模式
可在xml中设置,也可以在代码中的GoogleMapOptions设置
(1) xml中设置
§ map:liteMode="true"
(2) 代码中
· GoogleMapOptions options = new GoogleMapOptions().liteMode(true);
2.精简模式和map的生命周期
如果你要使用完全交互式的地图,你应该在activity的生命周期各个回调中也绑定地图的生命周期。生命周期方法包括 onCreate()、onDestroy()、onResume() 和 onPause();
在精简模式下使用 MapView 时,绑定生命周期可做可不做,但下列情况除外:
- 必须调用 onCreate(),否则将不会出现任何地图。
- 如果您想在精简模式地图上显示 My Location 圆点并使用默认位置来源,则需要调用 onResume() 和 onPause(),因为位置来源只会在这些调用的间隔期进行更新。如果您使用自己的位置来源,则不必调用这两个方法。
3.精简模式下的地图支持的api(除开以下,其他api的功能全部支持)
(1)标记 :支持部分
(2)摄像头位置、缩放比例和动画 :支持部分
(3)地图事件 :支持部分
(4)室内地图和建筑 :不支持
(5)Traffic 层 :不支持
(6)底面叠层 :不支持
(7)图块叠层 :不支持
(8)手势 :不支持
(9)Street View :不支持
(10)自定义样式 :不支持
三. StreetView
Google Street View 提供其整个覆盖区域内以指定道路为中心的 360 度全景视图。这里创建StreetViewPanoramaView或者StreetViewPanoramaFragment和创建map时类似,可以用xml方式,也可以用代码方式,只是全景图不支持xml定义初始化的属性,由于我自己的当前不用这个功能,这部分知识以后找机会补充上。
四. AndroidWear上运用google 地图
目前国内Android的穿戴设备还没正式兴起,反正不要和时代趋势作对就行了
五. 从其他应用用Intent调用Google地图
Google地图也对其他应用提供接口,可以通过Intent打开相应的google map的对应activity,这种方式方便并非开发地图应用但是又需要地图功能的应用程序,如果是需要嵌入完整地图功能的应用程序,则无需使用Intent方式,很明显,我目前就不用,以后再补充
六. 控件和手势
地图中有很多控件,例如指南针,放大缩小等控件,你可以通过UiSettings对象来操作这些控件,获取该对象的方式是
GoogleMap googleMap;
….
UiSettings settings =googleMap.getUiSettings();
1. 缩放放大控件(加号和减号那个)
可以在初始化配置时就显示出来,也可以在准备好了控件后通过UiSettings对象设置
初始化时:
(GoogleMapOptions)options.zoomControlsEnabled(true);
获取map后再设置
(UiSettings)uiSet. setZoomControlsEnabled(true);
2. 指南针图标,默认不可见,可以在初始化时设置,可以在获得map对像后设置,google说不能总是显示指南针,但是我实际运行是可以总是显示的,单击指南回到最初指向,双击指南针他就会消失,并回复到最初指向。
3. My Location按钮(像个准星,里面是个实心黑圆的东西,可以用来定位自己的位置)
仅当启用了 My Location 层时,My Location 按钮才会出现在屏幕的右上角。
4. 层级选择器(用于室内地图)
当用户查看室内地图时,层级选取器(楼层选取器)会出现在靠近屏幕中心右侧边缘位置。 如果有两个或更多个室内地图可见,层级选取器将应用于当前获得焦点的建筑,通常是最靠近屏幕中心的建筑。每栋建筑都具有首次显示选取器时默认选定的层级。用户可通过从选取器中进行选择来选择不同的层级。
您可以通过调用 GoogleMap.getUiSettings().setIndoorLevelPickerEnabled(boolean) 禁用或启用层级选取器控件。
如果您想用自己的层级选取器替换默认层级选取器,便可执行这项操作。
5. 地图工具栏(用于跳转到google地图应用,例如路线)
在精简模式下,这个工具栏始终显示,在全交互地图模式下,只有点击地图上的marker标记才会显示出,可通过如下代码进行禁用UiSettings.setMapToolbarEnabled(boolean)
6. 手势
有旋转手势,平移手势,倾斜手势,缩放手势,设置方式都是和上方的类似,都可提前初始配置或者通过UiSettings配置
七. 事件
1. 地图的点击/长按事件
获得GoogleMap对象后设置onMapClickListener监听或者onMapClickeListener监听,实现onMapClick(LatLng)或者onMapLongClick(LatLng)方法,LatLng是点击的经纬度对象
2. 精简模式下禁用点击(只能在精简模式下,我在全交互模式下设置这个,程序直接死掉)
对于MapView:
MapView view; ... view.setClickable(false);
对于MapFragment:
MapFragment fragment; ... fragment.getView().setClickable(false);
3. 摄像头变化事件监听
(GoogleMapmap.setOnCameraChangeListener(OnCameraChangeListener)进行设置,当摄像头发生变化时,侦听器通过onCameraChange(CameraPosition) 回调接收通知。 您随即便可获得摄像头的目标(纬度/经度)、缩放比例、方位和倾斜角度。可以保证在每次动画结束时调用该回调,但对于过渡帧,则不一定会调用该回调。
4. 室内地图事件
略,以后补充
5. 标记事件和信息窗口事件
您可以通过在标记所属的GoogleMap 对象上设置相应的侦听器来侦听和响应标记事件,包括标记点击和拖动事件。
八. 关于地图摄像头和视图
这部分,google api讲的是缩放倍数,摄像头倾斜时的视角图解,我这里就不好描述了
许多城市在放大查看时会显示 3D 建筑,您可以通过调用 GoogleMap.setBuildingsEnabled(false)禁用 3D 建筑。
1. 摄像头大的相关操作
无论是放大缩小还是移动摄像头,都和CameraUpdate的对象使用有关,而CamerUpdateFactory工具类能够创建许多不同功能的CameraUpdate对象(以下大多数方法都会返回CamerUpdate对象,如果不是我会特别标注)
(1) CameraUpdateFactory.zoomIn() 和 CameraUpdateFactory.zoomOut() 为您提供的 CameraUpdate 可将缩放比例更改 1.0
(2) CameraUpdateFactory.zoomTo(float)为您提供的 CameraUpdate 可将缩放比例更改为给定值
(3) CameraUpdateFactory.zoomBy(float)和CameraUpdateFactory.zoomBy(float, Point) 为您提供的 CameraUpdate 可使缩放比例增加(如果是负值,则减少)给定值。后者会将给定点固定在屏幕上以使其保持在同一位置(经度/纬度), 因此它可能会更改摄像头的位置以实现此目的。
(4) CameraUpdateFactory.newLatLng(LatLng)为您提供的 CameraUpdate 可更改摄像头的经度和纬度
CameraUpdateFactory.newLatLngZoom(LatLng,float) 为您提供的 CameraUpdate可更改摄像头的经度、纬度和缩放比例
(5) CameraPosition position = new CamerPosition(LatLng,float zoom,float tilt,float bearing)
CameraUpdateFactory.newCameraPosition(position),提供的 CameraUpdate 可将摄像头移至给定位置
(6) 如果你想使摄像机刚好包住你想看的全部区域,例如你想看全中国的领土,则可以使用LatLngBound对象
该对象需要传入两个LatLng对象,如果是中国,则选取中国领土最长对角线两个点的坐标建立LatLng对象即可。
private GoogleMap mMap;
…..
private LatLngBounds AUSTRALIA = new LatLngBounds(
new LatLng(-44, 113), new LatLng(-10, 154));
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(AUSTRALIA,0));
当你需要LatLngBound的中心位置时,直接LatLngBounds
.getCenter()
获取中心点坐标
(7) 平移:
CameraUpdateFactory.scrollBy(float,float) 为您提供的 CameraUpdate可相应更改摄像头的经度和纬度,使得地图按指定像素数移动。 正 x 值会使摄像头右移,带来地图左移的效果。正 y 值会使摄像头下移,带来地图上移的效果。 相反,负 x 值会使摄像头左移, 带来地图右移的效果;而负 y 值会使摄像头上移。 滚动是以摄像头当前朝向为参照物。例如,如果摄像头的方位角为 90 度,则东方“向上”。
(8) 啥都干
(9) 以下示例代码是移动摄像头常用的方式
· private static final LatLng SYDNEY = new LatLng(-33.88,151.21); private static final LatLng MOUNTAIN_VIEW = new LatLng(37.4, -122.1); private GoogleMap map; ... map.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 15)); map.animateCamera(CameraUpdateFactory.zoomIn()); map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null); CameraPosition cameraPosition = new CameraPosition.Builder() .target(MOUNTAIN_VIEW) // Sets the center of the map to Mountain View .zoom(17) // Sets the zoom .bearing(90)// Sets the orientation of the camera to east .tilt(30) // Sets the tilt of the camera to 30 degrees .build(); // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
九. 位置数据
这里主要讲的是让地图定位到自己设备的位置
1. 位置权限
- android.permission.ACCESS_COARSE_LOCATION – 允许 API 利用 WiFi 或移动蜂窝数据(或同时利用两者)来确定设备位置。API 返回的位置精确度大约相当于城市街区。
- android.permission.ACCESS_FINE_LOCATION – 允许 API 利用包括全球定位系统 (GPS) 在内的可用位置提供商以及 WiFi 和移动蜂窝数据尽可能精确地确定位置。
2. 请求运行时权限
这个主要是Android6.0的机型,在这个机型上,用户不需要在安装应用时确认应用需要哪些权限,而是在应用需要时弹出对话框示意用户需要某某权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { mMap.setMyLocationEnabled(true);//如果有这个权限,这里就启动地图的Mylocation层 } else { // Show rationale and request permission. }
以下代码示例通过实现支持库中的ActivityCompat.OnRequestPermissionsResultCallback 来处理权限请求的结果:
@Override
public void onRequestPermissionsResult(intrequestCode, String[] permissions, int[] grantResults) {
if (requestCode == MY_LOCATION_REQUEST_CODE) {
if (permissions.length == 1 &&
permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
} else {
// Permission was denied. Display an error message.
}
}
3. My Location层(用来定位自己的位置)
开启My Location层的方法
mMap.setMyLocationEnabled(true);
启用了 My Location 层时,My Location 按钮会出现在地图的右上角。当用户点击该按钮时,摄像头将设备的当前位置(若已知)显示为地图的中心。 设备处于静止状态时,地图以小蓝点指示该位置;
您可以通过调用UiSettings
对象.setMyLocationButtonEnabled(false)
完全禁止该按钮出现。
这个一般和google地图定位联合使用,要用到Google Play services Location API,后面再补充