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 NameLayout 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_HEREgoogle_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. 创建一个名为 zoomfloat 变量,并将该变量设置为所需的初始缩放级别。通过以下列表,您可以了解在每个缩放级别看到的地图细节水平:
  • 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。(以下代码使用 SupportMapFragmentSupportStreetViewPanoramaFragment 来支持低于 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. MapsActivityonCreate() 中,移除按 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 地图?

  • MapViewMapFragment
  • MapFragmentMapActivity
  • MapViewMapActivity
  • 仅限 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 着陆页