地图对象

在 API 中,地图由 GoogleMapMapFragment 类表示。

代码示例

GitHub 上的 ApiDemos 代码库包含相关示例,展示了如何使用 GoogleMap 对象和 SupportMapFragment

向 Android 应用添加地图

添加地图的基本步骤如下:

  1. (此步骤只需执行一次。)按照项目配置指南中的步骤获取 API,获得密钥,然后将所需属性添加到您的 Android 清单中。
  2. 向将会处理地图的 Activity 添加 Fragment 对象。最简单的方法是向 Activity 的布局文件添加一个 <fragment> 元素。
  3. 实现 OnMapReadyCallback 接口并使用 onMapReady(GoogleMap) 回调方法获取 GoogleMap 对象的句柄。GoogleMap 对象是地图本身的内部表示。要设置地图的视图选项,请修改其 GoogleMap 对象。
  4. 在 Fragment 上调用 getMapAsync() 以注册回调。

以下是有关各步骤的更多详情。

添加 Fragment

向 Activity 的布局文件添加 <fragment> 元素,以定义 Fragment 对象。在此元素中,将 android:name 属性设置为 "com.google.android.gms.maps.MapFragment"。此操作会自动为 Activity 附加 MapFragment

以下布局文件包含 <fragment> 元素:

<?xml version="1.0" encoding="utf-8"?>
    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        android:name="com.google.android.gms.maps.MapFragment"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    

您还可以向代码中的 Activity 添加 MapFragment。为此,请创建一个新的 MapFragment 实例,然后调用 FragmentTransaction.add() 以将 Fragment 添加到当前的 Activity

 mMapFragment = MapFragment.newInstance();
     FragmentTransaction fragmentTransaction =
             getFragmentManager().beginTransaction();
     fragmentTransaction.add(R.id.my_container, mMapFragment);
     fragmentTransaction.commit();
    

添加地图代码

要在应用内使用地图,您需要实现 OnMapReadyCallback 接口,并在 MapFragmentMapView 对象上设置该回调的实例。本教程使用的是 MapFragment,因为这是向应用添加地图的最常用方法。第一步是实现回调接口:

public class MainActivity extends FragmentActivity
        implements OnMapReadyCallback {
    ...
    }
    

在您的 ActivityonCreate() 方法中,将布局文件设置为内容视图。例如,如果布局文件的名称是 main.xml,请使用以下代码:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ...
    }
    

通过调用 FragmentManager.findFragmentById() 获取 Fragment 的句柄,并向其传递 <fragment> 元素的资源 ID。请注意,当您生成布局文件时,系统会自动将资源 ID R.id.map 添加到 Android 项目中。

然后,使用 getMapAsync() 在 Fragment 上设置回调。

MapFragment mapFragment = (MapFragment) getFragmentManager()
        .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    

使用 onMapReady(GoogleMap) 回调方法获取 GoogleMap 对象的句柄。回调将在地图做好使用准备时触发。它会提供 GoogleMap 的非空实例。举例来说,您可以使用 GoogleMap 对象为地图设置视图选项,或者添加标记。

@Override
    public void onMapReady(GoogleMap map) {
        map.addMarker(new MarkerOptions()
            .position(new LatLng(0, 0))
            .title("Marker"));
    }
    

地图对象

借助 Maps SDK for Android,您可以在 Android 应用中显示 Google 地图。这些地图与您在 Google 地图移动版 (GMM) 应用中所见的地图具有相同的外观,并且该 API 公开的许多功能也是相同的。GMM 应用与 Maps SDK for Android 显示的地图之间存在两个明显差异:

  • 该 API 显示的地图图块不包含任何个性化内容,如个性化智能图标。
  • 并非地图上的所有图标均可点击。例如,公交站点图标就无法点击。不过,您向地图添加的标记是可点击的,并且该 API 包含一个监听器回调接口,用于进行各种标记互动。

除了地图绘制功能外,该 API 还支持符合 Android 界面模式的一整套互动方式。例如,您可以通过定义可响应用户手势的监听器来设置与地图的互动。

使用地图对象时的关键类是 GoogleMap 类。GoogleMap 在您的应用内为地图对象建模。在您的界面中,地图将由 MapFragmentMapView 对象表示。

GoogleMap 会自动处理以下操作:

  • 连接到 Google 地图服务。
  • 下载地图图块。
  • 在设备屏幕上显示图块。
  • 显示各种控件,例如平移和缩放控件。
  • 通过移动和缩放地图响应平移和缩放手势。

除了这些自动操作外,您还可以使用该 API 的对象和方法来控制地图的行为。例如,GoogleMap 具有可响应地图上点击动作和触摸手势的回调方法。您还可以使用您向 GoogleMap 提供的对象在地图上设置标记图标并为其添加叠加层。

MapFragment

MapFragment 是 Android Fragment 类的子类,您可以使用它在 Android Fragment 中放置地图。MapFragment 对象充当地图的容器,并提供对 GoogleMap 对象的访问权限。

View 不同,Fragment 表示 Activity 中的一种行为或界面的某一部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格界面,也可以在多个 Activity 中重复使用某个 Fragment。如需了解详情,请参阅 Android 文档中有关 Fragment 的部分。

MapView

MapView 是 Android View 类的子类,您可用使用它在 Android View 中放置地图。View 表示屏幕的某个矩形区域,是 Android 应用和微件的基本构建块。与 MapFragment 类似,MapView 也充当地图的容器,通过 GoogleMap 对象显示核心地图功能。

完全互动模式下使用该 API 时,MapView 类的用户必须将以下 Activity 生命周期方法转发给 MapView 类中的相应方法:onCreate()onStart()onResume()onPause()onStop()onDestroy()onSaveInstanceState()onLowMemory()。GitHub 上的 ApiDemos 代码库包含一个示例,展示了如何转发 Activity 生命周期方法。在精简模式下使用该 API 时,转发生命周期事件为可选操作。如需了解详情,请参阅精简模式文档。

地图类型

Maps SDK for Android 内提供了许多类型的地图。地图的类型决定了地图的整体表现形式。例如,地图集通常包含侧重于显示边界的政治地图,而道路地图则会显示某个城市或地区的所有道路。

Maps SDK for Android 提供了四种类型的地图,以及不显示任何地图的选项:

普通地图
典型的道路地图。显示道路、人类建造的一些地图项以及河流等重要的自然地图项。此外,还会显示道路和地图项标签。
混合地图
添加了道路地图的卫星照片数据。此外,还会显示道路和地图项标签。
卫星地图
卫星照片数据。该地图不显示道路和地图项标签。
地形地图
地形数据。地图包含颜色、轮廓线和标签以及透视阴影。此外,还会显示一些道路和标签。
没有图块。该地图将渲染为未加载任何图块的空白网格。

更改地图类型

要设置地图类型,请调用 GoogleMap 对象的 setMapType() 方法,并传递 GoogleMap 中定义的某个类型常量。例如,要显示卫星地图,请使用以下代码:

GoogleMap map;
    ...
    // Sets the map type to be "hybrid"
    map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    

下图显示的是同一位置的普通地图、混合地图和地形地图之间的对比情况:

MapType 对比

室内地图

在较高的缩放级别下,地图会显示机场、商场、大型零售商店和公交站点等室内场所的楼层平面图。“普通”和“卫星”地图类型(GoogleMap.MAP_TYPE_NORMALGoogleMap.MAP_TYPE_SATELLITE)可显示这些楼层平面图(称为室内地图)。当用户放大地图时,楼层平面图会自动打开;当用户缩小地图时,楼层平面图会逐渐消失。

弃用通知:在未来的版本中,室内地图仅会在 normal 地图类型上显示。从该未来版本开始,satelliteterrainhybrid 地图将不支持室内地图。即使不支持室内地图,isIndoorEnabled() 也将继续返回通过 setIndoorEnabled() 设置的值,与它现在的处理方式相同。默认情况下,setIndoorEnabledtrue。您可以在版本说明中了解这些地图类型何时停止支持室内地图。

室内地图示例

在 API 中使用室内地图

下面概要列出了 API 中的室内地图功能:

  • 您可以通过调用 GoogleMap.setIndoorEnabled(false) 停用室内地图。默认情况下,室内地图处于启用状态。室内地图一次只能在一个地图上显示。默认情况下,这是您向应用添加的第一个地图。如果您想在其他地图上显示室内地图,请在第一个地图上停用室内地图,然后对第二个地图调用 setIndoorEnabled(true)
  • 要停用默认楼层选择器,请调用 GoogleMap.getUiSettings().setIndoorLevelPickerEnabled(false)。如需了解详情,请参阅与地图互动
  • 通过 GoogleMap 上的 OnIndoorStateChangeListener 接口,您可以设置在一栋新建筑物获得焦点或者激活建筑物内的新楼层时调用的监听器。如需了解详情,请参阅与地图互动
  • GoogleMap.getFocusedBuilding() 为您获取当前获得焦点的建筑物。然后,您可以通过调用 IndoorBuilding.getActiveLevelIndex() 找到当前的活动楼层。请参阅参考文档,以了解 IndoorBuilding 对象和 IndoorLevel 对象中提供的所有信息。

对基本地图进行样式设置不会影响室内地图。

添加楼层平面图

选择位置中提供了室内地图(楼层平面图)。如果您想在应用中突出显示的建筑物没有楼层平面图数据,则您可以执行以下操作:

  • 直接向 Google 地图添加楼层平面图。如果采用这种方式,Google 地图的所有用户均可看到您添加的楼层平面图。
  • 将楼层平面图作为地面叠加层图块叠加层显示在您的地图上。如果采用这种方式,只有您应用的用户才能查看您的楼层平面图。

路况图层

您可以授权用户查看在顶部叠加了交通密度信息的地图。这样可让用户直观了解本地的交通状况。您可以通过调用 setTrafficEnabled() 方法启用和停用路况图层,然后通过调用 isTrafficEnabled() 方法确定路况图层当前是否处于启用状态。以下示例展示了路况图层在地图上的可能显示方式。

显示路况图层的 Google 地图

配置初始状态

您可以通过 Maps API 配置地图的初始状态,以便满足应用的需求。您可以指定以下内容:

  • 相机位置,包括:位置、缩放级别、方位和倾斜角度。如需详细了解相机定位,请参阅相机和视图
  • 地图类型。
  • 是否在屏幕上显示缩放按钮和/或罗盘。
  • 用户在操纵相机时可使用的手势。
  • 是否启用了精简模式。精简模式地图是指地图的一种位图图像,它支持完整 API 提供的一部分功能。

如果您已将地图添加到 Activity 的布局文件,可以通过 XML 配置地图的初始状态;如果您是以编程方式添加地图,则可以编程方式进行配置。

使用 XML 属性

本部分介绍了在您利用 XML 布局文件向应用添加地图的情况下如何设置地图的初始状态。

Maps API 为 MapFragmentMapView 定义了一组自定义 XML 属性,您可以利用它们直接在布局文件内配置地图的初始状态。当前定义的属性如下:

  • mapType。您可以使用此属性指定要显示的地图类型。有效值包括:nonenormalhybridsatelliteterrain
  • cameraTargetLatcameraTargetLngcameraZoomcameraBearingcameraTilt。您可以使用这些属性指定相机的初始位置。如需详细了解相机位置及其属性,请参阅此处
  • uiZoomControlsuiCompass。您可以使用这两个属性指定是否要在地图上显示缩放控件和罗盘。如需了解详情,请参阅 UiSettings
  • uiZoomGesturesuiScrollGesturesuiRotateGesturesuiTiltGestures。您可以使用这些属性指定启用/停用哪些用于与地图互动的手势。如需了解详情,请参阅 UiSettings
  • zOrderOnTop。控制地图视图的表面是否位于其窗口的顶部。如需了解详情,请参阅 SurfaceView.setZOrderOnTop(boolean)。请注意,如果指定此属性,将会覆盖所有其他可能出现在地图上的视图(例如缩放控件、“我的位置”按钮)。
  • useViewLifecycle。此属性必须与 MapFragment 共同使用才能生效。此属性指定是否应将地图的生命周期与 Fragment 的视图或 Fragment 本身关联。如需了解详情,请参阅此处
  • liteMode。值 true 会将地图设置为精简模式。精简模式地图是指地图的一种位图图像,它支持完整 API 提供的一部分功能。此属性的默认值为 false

要在 XML 布局文件内使用上述自定义属性,您必须先添加以下命名空间声明。您可以选择任何命名空间,不一定要选择 map

xmlns:map="http://schemas.android.com/apk/res-auto"
    

然后您就可以像使用标准 Android 属性那样,向您的布局组件中添加带 map: 前缀的属性。

下面这段 XML 代码展示了如何配置带有一些自定义选项的 MapFragment。这些属性同样可以应用于 MapView

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

编程方式

本部分介绍了在您以编程方式向应用添加地图的情况下如何设置地图的初始状态。

如果您以编程方式添加了 MapFragment(或 MapView),则可以通过传递指定了选项的 GoogleMapOptions 对象配置其初始状态。可供您使用的选项与通过 XML 提供的选项完全相同。您可以创建下面这样的 GoogleMapOptions 对象:

GoogleMapOptions options = new GoogleMapOptions();
    

然后对其进行如下配置:

options.mapType(GoogleMap.MAP_TYPE_SATELLITE)
        .compassEnabled(false)
        .rotateGesturesEnabled(false)
        .tiltGesturesEnabled(false);
    

要在创建地图时应用这些选项,请执行下列操作之一:

地图内边距

这段视频展示了一个地图内边距示例。

Google 地图设计为填充由其容器元素(通常是 MapViewMapFragment)定义的整个区域。地图外观和行为的若干方面都由其容器的尺寸定义:

  • 相机的目标将反映含内边距的区域的中心。
  • 地图控件以地图边缘为参照物进行定位。
  • 版权声明或 Google 徽标等法律信息沿地图底部边缘显示。

您可以利用 GoogleMap.setPadding() 方法围绕地图边缘添加内边距。地图将继续填充整个容器,但文本和控件定位、地图手势以及相机移动将呈现出将地图置于较小空间时的行为。这会导致出现以下变化:

  • 通过 API 调用或按下按钮(例如罗盘按钮、“我的位置”按钮、缩放按钮)进行的相机移动将变成相对于内边距区域的移动。
  • getCameraPosition() 将返回含内边距的区域的中心。
  • Projection.getVisibleRegion() 将返回含内边距的区域。
  • 界面控件会按指定的像素数从容器边缘偏移。

设计与地图的某些部分重叠的界面时,内边距会很有用。例如,在以下图像中,地图沿顶部边缘和右侧边缘设置了内边距。可见地图控件和法律文本将沿带有内边距的区域的边缘显示(显示为绿色),而地图仍将继续填充整个容器(显示为蓝色)。在此示例中,您可以让菜单悬浮在地图右侧的上方,这样不会遮盖住地图控件。

地图内边距

对地图进行本地化

向应用添加 MapViewMapFragment 后,地图上的文本元素会根据用户的设备设置和位置以适当的语言显示。通过向您的 Gradle 文件添加 resConfigs 项,您可以将应用所使用的语言限制为一部分受支持的语言。这在移除未使用的语言时尤为有用,同时还可减少应用的二进制文件大小。例如:

defaultConfig {
        resConfigs "en", "fr", "es", "zh", "de", "ja", "ru", "ko", "pt", "in"
    }
    

详细了解将您的 Android 应用本地化