Android 09.1 高级课程:Google 地图

1. 欢迎

此 Codelab 是由 Google Developers 培训团队开发的“高级 Android 开发”培训课程的一部分。如果您按顺序学习这些 Codelab,将会充分发掘此课程的价值。

如需详细了解本课程,请参阅高级 Android 开发概览。

简介

使用 Google 地图构建应用,您可以向应用添加各种功能,例如卫星图像、强大的界面控件、位置信息跟踪和地点标记。您可以展示自己的数据集内的信息(例如有名钓鱼区或攀爬区的位置信息),从而为标准 Google 地图增加价值。您还可以创建与现实世界相关的游戏,例如《Pokemon Go》。

在此实践中,您将创建一个名为 Wander 的 Google 地图应用。

您应当已掌握的内容

您应熟悉以下内容:

  • Google 地图的基本功能。
  • 运行时权限。
  • 在 Android Studio 中创建、构建和运行应用。
  • 在 build.gradle 文件中添加外部库。

学习内容

  • 将 Google 地图集成到您的应用中。
  • 显示不同的地图类型。
  • 设置 Google 地图样式。
  • 向地图添加标记。
  • 允许用户在地图注点 (POI) 上放置标记。
  • 启用位置信息跟踪功能。
  • 启用 Google 街景。

您将执行的操作

  • 从 Google API 控制台获取 API 密钥并向应用注册此密钥。
  • 创建包含嵌入式 Google 地图的 Wander 应用。
  • 向应用添加自定义功能,例如标记、样式和位置跟踪。
  • 在应用中启用位置信息跟踪和街景。

2. 应用概览

在此实践中,您将创建 Wander 应用,该应用是一个设置了样式的 Google 地图。借助 Wander 应用,您可以将标记拖放到相应位置上、实时查看自己的位置,以及查看街景全景图片。

自定样式的 Google 地图

Android 应用中的 Google 街景

3. 任务 1. 设置项目并获取 API 密钥

与 Places API 一样,Google 地图 API 也需要 API 密钥。如需获取 API 密钥,请在 Google API 控制台中注册您的项目。该 API 密钥与将此应用关联到其作者的数字证书相关联。如需详细了解如何使用数字证书以及如何为应用签名,请参阅为应用签名。

在此实践中,您将使用调试证书的 API 密钥。如对您的调试 build 进行签名中所述,调试证书并不安全。使用 Google 地图 API 的已发布 Android 应用需要另一个 API 密钥,即发布证书的密钥。如需详细了解如何获取发布证书,请参阅获取 API 密钥。

Android Studio 包含一个 Google Maps Activity 模板,此模板可生成有用的模板代码。此模板代码包含一个 google_maps_api.xml 文件,其中包含一个可简化 API 密钥获取流程的链接。

1.1 使用地图模板创建 Wander 项目

  1. 新建一个 Android Studio 项目。
  2. 将新应用命名为“Wander”。接受默认设置,直到进入添加活动页面。
  3. 选择 Google Maps Activity 模板。
  4. 保留默认的 Activity Name 和 Layout Name。
  5. 将标题更改为“Wander”,然后点击 Finish。

Android Studio 会创建多个与地图相关的附加文件:

google_maps_api**.xml**

您可以使用此配置文件来保存 API 密钥。该模板会生成两个 google_maps_api.xml 文件:一个用于调试,一个用于发布。调试证书的 API 密钥文件位于 src/debug/res/values 中。发布证书的 API 密钥文件位于 src/release/res/values 中。在此实践中,我们仅使用调试证书。

activity_maps.xml

此布局文件包含一个填满整个屏幕的 fragment。SupportMapFragment 类是 Fragment 类的一个子类。您可以使用任何 ViewGroup 中的 <fragment> 标记在布局文件中添加 SupportMapFragment,并包含一个额外的属性:

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java

MapsActivity.java 文件实例化 SupportMapFragment 类,并使用该类的 getMapAsync() 方法来准备 Google 地图。包含 SupportMapFragment 的 activity 必须实现 OnMapReadyCallback 接口以及该接口的 onMapReady() 方法。getMapAsync() 方法会返回一个 GoogleMap 对象,表示地图已加载。

1.2 获取 API 密钥

  1. 打开 google_maps_api.xml 文件的调试版本。

该文件包含一个带有长网址的注释。此网址的参数包含应用的特定信息。

  1. 将此网址复制并粘贴到浏览器中。
  2. 按照提示在 Google API 控制台中创建项目。由于所提供网址中的参数,API 控制台知道要自动启用 Google Maps Android API
  3. 创建 API 密钥,然后点击限制密钥,以将密钥限制用于 Android 应用。生成的 API 密钥应以 AIza 开头。
  4. 在 google_maps_api.xml 文件中,将密钥粘贴到显示 YOUR_KEY_HERE 的 google_maps_key 字符串中。
  5. 运行应用。您应可以在 activity 中看到嵌入式地图,其中标记设置在澳大利亚悉尼。(悉尼标记是模板自带的,您稍后可以对其进行更改。)

4. 任务 2. 添加地图类型和标记

Google 地图包含多种地图类型:标准、混合、卫星、地形和“无”。在此任务中,您将添加一个包含选项菜单的应用栏,用户可在此菜单中更改地图类型。将地图的起始位置移至您的住宅位置。然后,您添加对标记的支持,标记指示地图上的单个位置,并可包含标签。

2.1 添加地图类型

用户需要的地图类型取决于他们需要的信息类型。在汽车中使用地图进行导航时,清晰地看到街道名称很有帮助。徒步旅行时,您可能更关心还要攀爬多长距离才能到达山顶。在此步骤中,您会添加一个包含选项菜单的应用栏,用户可在此菜单中更改地图类型。

  1. 如需创建新的菜单 XML 文件,请右键点击 res 目录,然后依次选择 New > Android Resource File。
  2. 在对话框中,将该文件命名为 map_options。选择 Menu 作为资源类型。点击确定。
  3. 将新文件中的代码替换为以下代码,以创建地图选项。“无”地图类型会被省略,因为“无”会使系统根本不包含任何地图。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never"/>
   <item android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never"/>
   <item android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never"/>
   <item android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never"/>
</menu>
  1. 为 title 属性创建字符串资源。
  2. 在 MapsActivity 文件中,将该类更改为扩展 AppCompatActivity 类,而不是扩展 FragmentActivity 类。使用 AppCompatActivity 将显示应用栏,因此也会显示菜单。
  3. 在 MapsActivity 中,替换 onCreateOptionsMenu() 方法并膨胀 map_options 文件:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
   MenuInflater inflater = getMenuInflater();
   inflater.inflate(R.menu.map_options, menu);
   return true;
}
  1. 如需更改地图类型,请对 GoogleMap 对象使用 setMapType() 方法,并传入某个地图类型常量。

替换 onOptionsItemSelected() 方法。粘贴以下代码,以便在用户选择某个菜单选项时更改地图类型:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       // Change the map type based on the user's selection.
       switch (item.getItemId()) {
           case R.id.normal_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
               return true;
           case R.id.hybrid_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
               return true;
           case R.id.satellite_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
               return true;
           case R.id.terrain_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
               return true;
           default:
               return super.onOptionsItemSelected(item);
       }
    }
  1. 运行应用。使用应用栏中的菜单更改地图类型。请注意地图外观的变化。

2.2 移动默认地图位置

默认情况下,onMapReady() 回调包含的代码会将标记放置在创建 Google 地图时所处的澳大利亚悉尼。默认回调还会以动画形式将地图平移到悉尼。在此步骤中,您将使地图平移到您的住宅位置,但不放置标记,然后缩放到您指定的级别。

  1. 在 onMapReady() 方法中,移除用于在悉尼放置标记并移动相机的代码。
  2. 在浏览器中前往 www.google.com/maps,然后找到您的住宅。
  3. 右键点击相应位置,然后选择这儿有什么?

屏幕底部附近会弹出一个小窗口,其中包含位置信息,包括纬度和经度。

  1. 创建一个名为 home 的新 LatLng 对象。在 LatLng 对象中,使用您在浏览器中从 Google 地图上找到的坐标。
  2. 创建一个名为 zoom 的 float 变量,并将该变量设置为所需的初始缩放级别。通过以下列表,您可以了解在每个缩放级别看到的地图细节水平:
  • 1:全球
  • 5:大陆/洲
  • 10:城市
  • 15:街道
  • 20:建筑物
  1. 使用 CameraUpdateFactory.newLatLngZoom() 创建一个 CameraUpdate 对象,并传入您的 LatLng 对象和 zoom 变量。通过对 GoogleMap 对象调用 moveCamera() 并传入新的 CameraUpdate 对象,平移和缩放相机:
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(home, zoom));
  1. 运行应用。地图应该会平移到您的住宅,并缩放到所需级别。

2.3 添加地图标记

Google 地图可以使用标记来突出显示某个位置,您可以使用 Marker 类创建标记。默认标记使用标准的 Google 地图图标:Google 地图标记

您可以扩展标记,以在信息窗口中显示背景信息。

在此步骤中,您将在用户轻触并按住地图上的某个位置时添加一个标记。然后,您会添加一个 InfoWindow,用于在用户点按标记时显示标记坐标。

放置的图钉的信息窗口

  1. 在 MapsActivity 中创建一个名为 setMapLongClick() 的方法桩,此方法桩把 final GoogleMap 作为参数并返回 void:
private void setMapLongClick(final GoogleMap map) {}
  1. 使用 GoogleMap 对象的 setOnMapLongClickListener() 方法在用户轻触并按住的位置放置标记。传入 OnMapLongClickListener 的新实例,该实例会替换 onMapLongClick() 方法。传入的实参是一个 LatLng 对象,其中包含用户按下的位置的坐标:
private void setMapLongClick(final GoogleMap map) {
   map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
       @Override
       public void onMapLongClick(LatLng latLng) {
       }
   });
}
  1. 在 onMapLongClick() 内,调用 addMarker() 方法。传入一个新的 MarkerOptions 对象,并将位置设置为传入的 LatLng:
map.addMarker(new MarkerOptions().position(latLng));
  1. 在 onMapReady() 方法结束时调用 setMapLongClick()。传入 mMap。
  2. 运行应用。在地图上轻触并按住,在某个位置上放置标记。
  3. 点按此标记,让其在屏幕上居中显示。

导航按钮会显示在屏幕左下角,以便用户使用 Google 地图应用导航到标记的位置。

如需为标记添加信息窗口,请执行以下操作:

  1. 在 MarkerOptions 对象中,设置 title 字段和 snippet 字段。
  2. 在 onMapLongClick() 中,将 title 字段设置为“Dropped Pin”。将 snippet 字段设置为 addMarker() 方法内的位置坐标。
map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
   @Override
   public void onMapLongClick(LatLng latLng) {
       String snippet = String.format(Locale.getDefault(),
               "Lat: %1$.5f, Long: %2$.5f",
               latLng.latitude,
               latLng.longitude);

       map.addMarker(new MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet));
   }
});
  1. 运行应用。在地图上轻触并按住以放置地点标记。点按此标记可显示信息窗口。

2.4 添加 POI 监听器

默认情况下,地图注点 (POI) 将与对应的图标一起显示在地图上。POI 包括公园、学校和政府大楼,等等。当地图类型设为 normal 时,商家 POI 也会显示在地图上。商家地图注点表示商店、餐馆和酒店之类的商家。

在这一步中,您将向地图添加 GoogleMap.OnPoiClickListener。此点击监听器会立即在地图上放置标记,而不是等待用户轻触并按住。此点击监听器还会显示包含 POI 名称的信息窗口。

地图注点标记

  1. 在 MapsActivity 中创建一个名为 setPoiClick() 的方法桩,此方法桩把 final GoogleMap 作为实参,并返回 void:
private void setPoiClick(final GoogleMap map) {}
  1. 在 setPoiClick() 方法中,对传入的 GoogleMap 设置 OnPoiClickListener:
map.setOnPoiClickListener(new GoogleMap.OnPoiClickListener() {
   @Override
   public void onPoiClick(PointOfInterest poi) {
   }
});
  1. 在 onPoiClick() 方法中,在 POI 位置放置标记。将标题设置为地图注点的名称。将结果保存到名为 poiMarker 的变量中。
public void onPoiClick(PointOfInterest poi) {
   Marker poiMarker = mMap.addMarker(new MarkerOptions()
       .position(poi.latLng)
       .title(poi.name);
}
  1. 对 poiMarker 调用 showInfoWindow(),系统会立即显示信息窗口。
poiMarker.showInfoWindow();
  1. 在 onMapReady() 结束时调用 setPoiClick()。传入 mMap。
  2. 运行应用并找到 POI,例如公园。点按 POI,在其上放置标记,并在信息窗口中显示该 POI 的名称。

5. 任务 3. 设置地图样式

您可以通过多种方式自定义 Google 地图,让地图拥有独特的外观和风格。

您可以使用可用的 XML 属性自定义 MapFragment 对象,就像自定义任何其他 fragment 一样。但在此步骤中,您将使用 GoogleMap 对象上的方法自定义 MapFragment 的内容的外观和风格。您可以使用在线样式向导为地图添加样式并自定义标记。您还可以向家庭住址添加一个随地图缩放和旋转的 GroundOverlay。

3.1 为地图添加样式

若要为您的地图创建自定义样式,您需要生成一个 JSON 文件,以指定地图中地图项的显示方式。您无需手动创建此 JSON 文件:Google 提供了样式设置向导,可在您直观地设置地图样式后生成 JSON。在此实践中,您将为地图设置“夜间模式”样式,这意味着地图会使用暗淡的颜色和低对比度,以便在夜间使用。

  1. 在浏览器中前往 https://mapstyle.withgoogle.com/。
  2. 选择 Create a Style。
  3. 选择夜间主题。
  4. 点击菜单底部的更多选项。
  5. 在地图项类型列表底部,依次选择水域 > 填充。将水域的颜色更改为深蓝色(例如 #160064)。
  6. 点击完成。从随即显示的弹出式窗口中复制 JSON 代码。
  7. 在 Android Studio 中,在 res 目录中创建一个名为 raw 的资源目录。在 res/raw 中创建名为 map_style.json 的文件。
  8. 将 JSON 代码粘贴到新的资源文件中。
  9. 如需将 JSON 样式设置为地图,请对 GoogleMap 对象调用 setMapStyle()。传入一个 MapStyleOptions 对象,以加载 JSON 文件。setMapStyle() 方法会返回一个布尔值,指示样式设置是否成功。如果无法加载文件,该方法会抛出 Resources.NotFoundException。

将以下代码复制到 onMapReady() 方法中,以设置地图的样式。您可能需要为日志语句创建 TAG 字符串:

     try {
        // Customize the styling of the base map using a JSON object defined
        // in a raw resource file.
        boolean success = googleMap.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
                   this, R.raw.map_style));

        if (!success) {
            Log.e(TAG, "Style parsing failed.");
        }
     } catch (Resources.NotFoundException e) {
        Log.e(TAG, "Can't find style. Error: ", e);
     }
  1. 运行应用。当地图处于 normal 模式时,应会显示新样式。

采用夜间模式样式的 Google 地图

3.2 设置标记的样式

通过设置地图标记的样式,您可以进一步对地图进行个性化设置。在此步骤中,您将更改默认的红色标记,使其与夜间模式配色方案相匹配。

  1. 在 onMapLongClick() 方法中,将以下代码行添加到 MarkerOptions() 构造函数中,以便使用默认标记,但将颜色更改为蓝色:
.icon(BitmapDescriptorFactory.defaultMarker
       (BitmapDescriptorFactory.HUE_BLUE))
  1. 运行应用。您放置的标记现在会显示蓝色阴影,这与应用的夜间模式主题更加一致。

请注意,由于您未向 onPoiClick() 方法添加样式,因此 POI 标记仍显示为红色。

3.3 添加叠加层

您可以自定义 Google 地图,其中一个方法是在 Google 地图上进行绘制。如果您想突出特定类型的地点(例如热门钓鱼地点),此方法就会有用。支持以下三种类型的叠加层:

  • 形状:您可以向地图添加多段线、多边形和圆形。
  • TileOverlay 对象:图块叠加层用于定义在基本地图图块之上添加的一组图片。如果您要为地图添加大量图像,就需要使用图块叠加层。典型的图块叠加层覆盖大片地理区域。
  • GroundOverlay 对象:底面叠层是固定在地图上的图像。与标记不同,底面叠层朝向地球表面,而不是屏幕。旋转、倾斜或缩放地图会改变图片的朝向。如果您想将单个图像固定在地图上的某一区域,便可使用地面叠加层

在此步骤中,您会将 Android 形状的底面叠层添加到您的住宅位置。

  1. 下载此 Android 映像并将其保存到您的 res/drawable 文件夹中。
  2. 在 onMapReady() 中,在调用将相机移动到住宅位置后,创建一个 GroundOverlayOptions 对象。将该对象分配给名为 homeOverlay 的变量:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions();
  1. 使用 BitmapDescriptorFactory.fromResource() 方法,利用上述图片创建 BitmapDescriptor 对象。将该对象传递给 GroundOverlayOptions 对象的 image() 方法:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
    .image(BitmapDescriptorFactory.fromResource(R.drawable.android));
  1. 通过调用 position() 方法为 GroundOverlayOptions 对象设置 position 属性。传入 home LatLng 对象和 float(以米为单位,表示所需叠加层的宽度)。在本例中,100 米的宽度效果较好:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
     .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
       .position(home, 100);
  1. 对 GoogleMap 对象调用 addGroundOverlay()。传入您的 GroundOverlayOptions 对象:
mMap.addGroundOverlay(homeOverlay);
  1. 运行应用。放大您的住宅位置,您会看到 Android 图像作为叠加层。

6. 任务 4. 启用位置信息跟踪和街景视图

用户经常使用 Google 地图查看自己的当前位置,您可以使用位置信息服务 API 获取设备位置信息。如需在地图上显示设备位置,但不再进一步使用 Location 数据,可以使用位置数据图层。

位置数据层会在地图的右上角添加我的位置按钮。当用户点按此按钮时,地图将以设备所在位置为中心。设备处于静止状态时,位置以蓝点显示;设备处于移动状态时,位置以蓝色 V 形显示。

一个带有位置跟踪功能的样式化 Google 地图

您可以使用 Google 街景(这是某个指定位置的可导航全景照片)提供有关某个位置的更多信息。

在此任务中,您将启用位置数据层和街景,以便当用户点按地图注点标记的信息窗口时,地图进入街景模式。

4.1 启用位置信息跟踪功能

如需在 Google 地图中启用位置信息跟踪功能,只需一行代码即可。但是,您必须确保用户已授予位置信息权限(使用运行时权限模式)。

在此步骤中,您会请求位置信息权限并启用位置信息跟踪。

  1. 在 AndroidManifest.xml 文件中,验证 FINE_LOCATION 权限是否已存在。当您选择了 Google 地图模板时,Android Studio 会插入此权限。
  2. 如需在应用中启用位置跟踪功能,请在 MapsActivity 中创建一个名为 enableMyLocation() 的方法,该方法不带参数也不返回任何内容。
  3. 定义 enableMyLocation() 方法。检查 ACCESS_FINE_LOCATION 权限。如果已授予该权限,请启用位置图层。否则,请申请该权限:
private void enableMyLocation() {
   if (ContextCompat.checkSelfPermission(this,
           Manifest.permission.ACCESS_FINE_LOCATION)
           == PackageManager.PERMISSION_GRANTED) {
       mMap.setMyLocationEnabled(true);
   } else {
       ActivityCompat.requestPermissions(this, new String[]
                       {Manifest.permission.ACCESS_FINE_LOCATION},
               REQUEST_LOCATION_PERMISSION);
   }
}
  1. 从 onMapReady() 回调中调用 enableMyLocation(),以启用位置图层。
  2. 替换 onRequestPermissionsResult() 方法。如果已授予权限,请调用 enableMyLocation():
@Override
public void onRequestPermissionsResult(int requestCode,
       @NonNull String[] permissions,
       @NonNull int[] grantResults) {
   // Check if location permissions are granted and if so enable the
   // location data layer.
   switch (requestCode) {
       case REQUEST_LOCATION_PERMISSION:
           if (grantResults.length > 0
                   && grantResults[0]
                   == PackageManager.PERMISSION_GRANTED) {
               enableMyLocation();
               break;
           }
   }
}
  1. 运行应用。现在,右上角包含我的位置按钮,用于显示设备的当前位置。

4.2 启用街景

Google 地图提供街景功能,可显示某个地点的全景视图,并提供用于沿指定路径导航的控件。街景功能并非覆盖全球。

在此步骤中,您将启用街景全景图片,当用户点按某个 POI 的信息窗口时,系统会激活该全景图片。您需要执行以下两项操作:

  1. 将地图注点标记与其他标记区分开来,因为您希望应用的功能仅在地图注点标记上起作用。这样,您就可以在用户点按某个地图注点信息窗口时启动街景,但不会在用户点按任何其他类型的标记时启动街景。

Marker 类包含一个 setTag() 方法,可用于附加数据。(数据可以是任何从 Object 扩展的数据)。您将为用户点击 POI 时创建的标记设置标记。

  1. 当用户在 OnInfoWindowClickListener 中点按已添加标记的信息窗口时,将 MapFragment 替换为 StreetViewPanoramaFragment。(以下代码使用 SupportMapFragment 和 SupportStreetViewPanoramaFragment 来支持低于 API 12 的 Android 版本。)

如果任何 fragment 在运行时发生变化,您必须在包含的 Activity 类中添加它们,而不是在 XML 中静态添加。

标记地图注点

  1. 在 onPoiClick() 回调中,对 poiMarker 调用 setTag()。传入任意字符串:
poiMarker.setTag("poi");

将静态 SupportMapFragment 替换为运行时实例

  1. 打开 activity_maps.xml 并将元素更改为将用作 fragment 容器的帧布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/fragment_container"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />
  1. 在 MapsActivity 的 onCreate() 中,移除按 ID 查找 SupportMapFragment 的代码,因为 XML 中不再有静态 SupportMapFragment。请改为通过调用 SupportMapFragment.newInstance() 创建 SupportMapFragment 的新运行时实例:
SupportMapFragment mapFragment = SupportMapFragment.newInstance();
  1. 使用包含 FragmentManager 的 fragment 事务将 fragment 添加到 FrameLayout:
getSupportFragmentManager().beginTransaction()
       .add(R.id.fragment_container, mapFragment).commit();
  1. 保留触发地图异步加载的代码行:
mapFragment.getMapAsync(this);

设置 OnInfoWindowClickListener 并检查标记标记

  1. 在 MapsActivity 中创建一个名为 setInfoWindowClickToPanorama() 的方法桩,此方法桩把 GoogleMap 作为参数并返回 void:
private void setInfoWindowClickToPanorama(GoogleMap map) {}
  1. 将 OnInfoWindowClickListener 设置为 GoogleMap:
map.setOnInfoWindowClickListener(
       new GoogleMap.OnInfoWindowClickListener() {
           @Override
           public void onInfoWindowClick(Marker marker) {
           }
       });
  1. 在 onInfoWindowClick() 方法中,检查标记是否包含您在 onPoiClick() 方法中设置的字符串标记:
if (marker.getTag() == "poi") {}

将 SupportMapFragment 替换为 SupportStreetViewPanoramaFragment

  1. 如果标记包含该标记,请使用 StreetViewPanoramaOptions 对象指定街景全景图片的位置。将对象的 position 属性设置为传入标记的位置:
StreetViewPanoramaOptions options =
       new StreetViewPanoramaOptions().position(
               marker.getPosition());
  1. 创建 SupportStreetViewPanoramaFragment 的新实例,并传入您创建的 options 对象:
SupportStreetViewPanoramaFragment streetViewFragment
       = SupportStreetViewPanoramaFragment
       .newInstance(options);
  1. 启动 fragment 事务。将 fragment 容器的内容替换为新的 fragment streetViewFragment。将事务添加到返回堆栈,以便按返回键时返回到 SupportMapFragment,而不是退出应用:
getSupportFragmentManager().beginTransaction()
       .replace(R.id.fragment_container,
               streetViewFragment)
       .addToBackStack(null).commit();
  1. 在调用 setPoiClick(). 之后,在 onMapReady() 中调用 setInfoWindowClickToPanorama(mMap)
  2. 运行应用。放大到有 街景覆盖范围的城市,例如山景城(Google 总部所在地),然后找到一个地图注点,例如公园。点按 POI 以放置标记并显示信息窗口。点按信息窗口,即可进入标记位置的街景模式。按返回按钮,返回到地图 fragment。

Android 应用中的 Google 街景

7. 解决方案代码

Wander 解决方案代码。

8. 编码挑战

挑战:如果您点按没有街景覆盖范围的位置中的某个 POI 的信息窗口,则会看到黑屏。

9. 总结

  • 若要使用地图 API,您需要使用 Google API 控制台中的 API 密钥。
  • 在 Android Studio 中,使用 Google 地图 Activity 模板会在应用布局中生成一个 Activity,其中包含一个 SupportMapFragment。该模板还会将 ACCESS_FINE_PERMISSION 添加到应用清单中,在 activity 中实现 OnMapReadyCallback,并替换所需的 onMapReady() 方法。

如需在运行时更改 GoogleMap 的地图类型,请使用 GoogleMap.setMapType() 方法。Google 地图可为以下地图类型之一:

  • 正常:典型的道路地图。显示道路、人类建造的一些特征以及河流等重要的自然特征。此外,还会显示道路和景观标签。
  • 混合:添加了道路地图的卫星照片数据。此外,还会显示道路和景观标签。
  • 卫星:照片数据。不显示道路和景观标签。
  • 地形:地形数据。地图包含颜色、轮廓线和标签以及透视阴影。此外,还会显示一些道路和标签。
  • 无**:** 无地图。

关于 Google 地图:

  • 标记是特定地理位置的指示符。
  • 点按时,标记的默认行为是显示包含该位置相关信息的信息窗口。
  • 默认情况下,地图注点 (POI) 将与对应的图标一起显示在基本地图上。POI 包括公园、学校和政府大楼,等等。
  • 此外,如果地图类型为 normal,商家 POI(商店、餐馆、酒店等)会默认显示在地图上。
  • 您可以使用 OnPoiClickListener 获取 POI 的点击次数。
  • 您可以使用样式向导更改 Google 地图几乎所有元素的视觉外观。样式向导会生成 JSON 文件,您使用 setMapStyle() 方法将其传递到 Google 地图中。
  • 您可以通过更改默认颜色,或用自定义图像替换标记图标来自定义标记。

其他重要信息:

  • 使用底面叠层将图像固定在某个地理位置。
  • 使用 GroundOverlayOptions 对象指定图像、图像的大小(以米为单位)以及图像的位置。将此对象传递给 GoogleMap.addGroundOverlay() 方法以将叠加层设置为地图。
  • 如果您的应用具有 ACCESS_FINE_LOCATION 权限,您可以使用 mMap.setMyLocationEnabled(true) 方法启用位置信息跟踪功能。
  • Google 街景提供整个报道地区内以指定道路为中心的 360 度全景视图。
  • 使用 StreetViewPanoramaFragment.newInstance() 方法创建新的街景 fragment。
  • 如需指定视图的选项,请使用 StreetViewPanoramaOptions 对象。将对象传递给 newInstance() 方法。

10. 了解更多内容

相关概念文档位于 9.1:Google 地图 API 中。

Android 开发者文档:

参考文档:

11. 家庭作业

此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:

  • 根据需要布置作业。
  • 告知学生如何提交家庭作业。
  • 给家庭作业评分。

讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。

如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。

构建并运行应用

  1. 创建一个使用 Google 地图 Activity 模板的新应用,该模板会在应用启动时加载 Google 地图。
  2. 当 Google 地图加载完毕后,将镜头移动到您的学校位置、住宅位置或对您有意义的其他位置。
  3. 向地图添加两个标记,一个位于学校位置,另一个位于您的住宅或其他有意义的位置。
  4. 您可以通过更改默认颜色,或用自定义图像替换默认标记图标来自定义标记图标。

提示:请参阅 onMapReady (GoogleMap googleMap) 文档。

回答以下问题

问题 1

当地图在应用中加载完毕并可供使用时,系统会调用哪个方法?

问题 2

您可以使用哪些 Android 组件在应用中添加 Google 地图?

  • MapView和MapFragment
  • MapFragment 和 MapActivity
  • MapView和MapActivity
  • 仅限 MapFragment

问题 3

Google Maps Android API 提供哪些类型的地图?

  • 普通地图、混合地图、地形图、卫星地图和路线图
  • 标准、混合、地形、卫星和“无”
  • 混合、地形、卫星、路线图和“无”
  • 标准、地形、卫星、图片地图和“无”

问题 4

您需要实现哪个接口才能向地图注点 (POI) 添加点击时功能?

  • GoogleMap.OnPoiListener
  • GoogleMap.OnPoiClickListener
  • GoogleMap.OnPoiClick
  • GoogleMap.OnPoiClicked

提交应用以进行评分

评分者的评分指南

检查应用是否具有以下功能:

  • 启动应用后,Google 地图会正确显示,这表明 API 密钥已正确生成。
  • Google 地图加载完毕后,摄像头会移动到学生的住宅或学校位置。在代码中,此步骤应在 onMapReady (GoogleMap googleMap) 回调方法中进行。
  • 标记会显示在学生的学校位置和另一个位置(例如学生的住址)处。
  • 这两个标记都经过了自定义。例如,标记使用的颜色不是默认的红色,或者使用了自定义图标。

12. 下一个 Codelab

如需查看“高级 Android 开发”培训课程中的所有 Codelab,请访问“高级 Android 开发”Codelab 着陆页。