街景

Google 街景提供整个覆盖区域内以指定道路为中心的 360 度全景视图。

这段视频展示了如何利用街景服务让您的用户在查看地图上的地址时获得身临其境般的体验,从而为他们提供有关其目的地或所关注的任何地点的实用背景信息。

通过 Google Maps Android API v2 提供的覆盖范围与您的 Android 设备上 Google 地图应用的覆盖范围相同。您可以在关于街景中阅读更多有关街景的内容,并通过交互地图查看支持的区域。

StreetViewPanorama 类可在您的应用中为街景全景图片建模。在您的界面中,全景图片由 StreetViewPanoramaFragmentStreetViewPanoramaView 对象表示。

代码示例

GitHub 上的 ApiDemos 代码库包含相关示例,展示了如何使用街景:

Java 示例

Kotlin 示例

Maps SDK for Android 中的街景概览

Maps SDK for Android 提供了用于获取和处理 Google 街景中使用的图像的街景服务。图片以全景图片的形式返回。

每张街景全景图片都是一个或一组图片,提供以单个位置为中心的 360 度全景视图。图片符合等矩形投影(圆柱投影),包含 360 度的水平视角(完整环绕)和 180 度垂直视角(直上直下)。生成的 360 度全景图片定义了一个球面投影,其中图片包绕在该球面的二维表面上。

StreetViewPanorama 提供了一个查看器,通过中心位置的相机将全景图片渲染为一个球面。您可以通过操纵 StreetViewPanoramaCamera 来控制相机的缩放级别和朝向(倾斜度和方位)。

使用入门

按照入门指南设置 Maps SDK for Android 项目。然后按下文所述添加街景全景图片。

Google Play 服务 SDK 客户端库提供了几个街景示例应用,您可以将它们导入项目,以其为基础开发应用。请参阅简介,获得有关导入示例应用的指导。

使用 API

按照以下说明向 Android Fragment 添加街景全景图片。这是向您的应用添加街景的最简单方法。然后阅读更多有关 Fragment、视图和自定义全景图片的内容。

添加街景全景图片

按照以下步骤添加如下示例所示的街景全景图片:

街景全景图片演示

步骤简述:

  1. 向将用于处理街景全景图片的 activity 添加一个 fragment 对象。最简单的方法是向 Activity 的布局文件添加一个 <fragment> 元素。
  2. 实现 OnStreetViewPanoramaReadyCallback 接口并使用 onStreetViewPanoramaReady(StreetViewPanorama) 回调方法获取 StreetViewPanorama 对象的句柄。
  3. 对 fragment 调用 getStreetViewPanoramaAsync() 以注册回调。

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

添加 fragment

向 activity 的布局文件添加 <fragment> 元素,以定义 fragment 对象。在此元素中,将 class 属性设置为 com.google.android.gms.maps.StreetViewPanoramaFragment(或 SupportStreetViewPanoramaFragment)。

以下是一个布局文件中的 Fragment 示例:

<fragment
    android:name="com.google.android.gms.maps.StreetViewPanoramaFragment"
    android:id="@+id/streetviewpanorama"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

添加街景代码

如需在应用内使用街景全景图片,您需要实现 OnStreetViewPanoramaReadyCallback 接口,并对 StreetViewPanoramaFragmentStreetViewPanoramaView 对象设置该回调的实例。本教程使用的是 StreetViewPanoramaFragment,因为这是向应用添加街景的最简单方法。第一步是实现回调接口:

Java

class StreetViewActivity extends AppCompatActivity implements OnStreetViewPanoramaReadyCallback {
    // ...
}
      

Kotlin

internal class StreetViewActivity : AppCompatActivity(), OnStreetViewPanoramaReadyCallback {
    // ...
        // ...
    }

    override fun onStreetViewPanoramaReady(streetViewPanorama: StreetViewPanorama) {
        val sanFrancisco = LatLng(37.754130, -122.447129)
        streetViewPanorama.setPosition(sanFrancisco)
    }

    private fun newView() {
        val sanFrancisco = LatLng(37.754130, -122.447129)
        val view = StreetViewPanoramaView(
            this,
            StreetViewPanoramaOptions().position(sanFrancisco)
        )
    }

    private fun setLocationOfThePanorama(streetViewPanorama: StreetViewPanorama) {
        val sanFrancisco = LatLng(37.754130, -122.447129)

        // Set position with LatLng only.
        streetViewPanorama.setPosition(sanFrancisco)

        // Set position with LatLng and radius.
        streetViewPanorama.setPosition(sanFrancisco, 20)

        // Set position with LatLng and source.
        streetViewPanorama.setPosition(sanFrancisco, StreetViewSource.OUTDOOR)

        // Set position with LaLng, radius and source.
        streetViewPanorama.setPosition(sanFrancisco, 20, StreetViewSource.OUTDOOR)

        streetViewPanorama.location.links.firstOrNull()?.let { link: StreetViewPanoramaLink ->
            streetViewPanorama.setPosition(link.panoId)
        }
    }

    private fun zoom(streetViewPanorama: StreetViewPanorama) {
        val zoomBy = 0.5f
        val camera = StreetViewPanoramaCamera.Builder()
            .zoom(streetViewPanorama.panoramaCamera.zoom + zoomBy)
            .tilt(streetViewPanorama.panoramaCamera.tilt)
            .bearing(streetViewPanorama.panoramaCamera.bearing)
            .build()
    }

    private fun pan(streetViewPanorama: StreetViewPanorama) {
        val panBy = 30f
        val camera = StreetViewPanoramaCamera.Builder()
            .zoom(streetViewPanorama.panoramaCamera.zoom)
            .tilt(streetViewPanorama.panoramaCamera.tilt)
            .bearing(streetViewPanorama.panoramaCamera.bearing - panBy)
            .build()
    }

    private fun tilt(streetViewPanorama: StreetViewPanorama) {
        var tilt = streetViewPanorama.panoramaCamera.tilt + 30
        tilt = if (tilt > 90) 90f else tilt
        val previous = streetViewPanorama.panoramaCamera
        val camera = StreetViewPanoramaCamera.Builder(previous)
            .tilt(tilt)
            .build()
    }

    private fun animate(streetViewPanorama: StreetViewPanorama) {
        // Keeping the zoom and tilt. Animate bearing by 60 degrees in 1000 milliseconds.
        val duration: Long = 1000
        val camera = StreetViewPanoramaCamera.Builder()
            .zoom(streetViewPanorama.panoramaCamera.zoom)
            .tilt(streetViewPanorama.panoramaCamera.tilt)
            .bearing(streetViewPanorama.panoramaCamera.bearing - 60)
            .build()
        streetViewPanorama.animateTo(camera, duration)
    }
}
      

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

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_street_view);
    SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
        (SupportStreetViewPanoramaFragment) getSupportFragmentManager()
            .findFragmentById(R.id.street_view_panorama);
    streetViewPanoramaFragment.getStreetViewPanoramaAsync(this);
}
      

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_street_view)
    // ...
}
      

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

然后,使用 getStreetViewPanoramaAsync() 对 fragment 设置回调。

Java

SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
    (SupportStreetViewPanoramaFragment) getSupportFragmentManager()
        .findFragmentById(R.id.street_view_panorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(this);
      

Kotlin

val streetViewPanoramaFragment =
    supportFragmentManager
        .findFragmentById(R.id.street_view_panorama) as SupportStreetViewPanoramaFragment
streetViewPanoramaFragment.getStreetViewPanoramaAsync(this)
      

使用 onStreetViewPanoramaReady(StreetViewPanorama) 回调方法来检索可直接使用的 StreetViewPanorama 的非空实例。

Java

@Override
public void onStreetViewPanoramaReady(StreetViewPanorama streetViewPanorama) {
    LatLng sanFrancisco = new LatLng(37.754130, -122.447129);
    streetViewPanorama.setPosition(sanFrancisco);
}
      

Kotlin

override fun onStreetViewPanoramaReady(streetViewPanorama: StreetViewPanorama) {
    val sanFrancisco = LatLng(37.754130, -122.447129)
    streetViewPanorama.setPosition(sanFrancisco)
}
      

有关配置初始状态的详细信息

与使用地图时不同,无法通过 XML 来配置街景全景图片的初始状态。不过,您可以通过传入包含所指定选项的 StreetViewPanoramaOptions 对象,以程序化方式配置全景图片。

Java

LatLng sanFrancisco = new LatLng(37.754130, -122.447129);
StreetViewPanoramaView view = new StreetViewPanoramaView(this,
    new StreetViewPanoramaOptions().position(sanFrancisco));
      

Kotlin

val sanFrancisco = LatLng(37.754130, -122.447129)
val view = StreetViewPanoramaView(
    this,
    StreetViewPanoramaOptions().position(sanFrancisco)
)
      

有关 StreetViewPanoramaFragment 的详细信息

StreetViewPanoramaFragmentAndroid fragment 类的子类,您可使用它在 Android fragment 中放置街景全景图片。StreetViewPanoramaFragment 对象充当全景图片的容器,并提供对 StreetViewPanorama 对象的访问权限。

StreetViewPanoramaView

StreetViewPanoramaView 是 Android View 类的子类,您可以使用它在 Android View 中放置街景全景图片。View 表示屏幕的某个矩形区域,是 Android 应用和微件的基本构建块。与 StreetViewPanoramaFragment 类似,StreetViewPanoramaView 也充当全景图片的容器,通过 StreetViewPanorama 对象显示核心功能。此类的用户必须将所有 Activity 生命周期方法(例如,onCreate()onDestroy()onResume()onPause()))都转发给 StreetViewPanoramaView 类中的相应方法。

自定义用户控制功能

默认情况下,用户在查看街景全景图片时可使用以下功能:平移、缩放和前往相邻全景图片。您可以通过 StreetViewPanorama 上的方法启用和停用用户控制手势。停用手势时,仍可通过编程方式做出更改。

设置全景图片的位置

如需设置街景全景图片的位置,请调用 StreetViewPanorama.setPosition() 并传递 LatLng。您还可以将 radiussource 作为可选参数传递。

如果您想扩大或缩小街景在其中寻找匹配全景图片的区域,就可以使用半径。半径为 0 意味着必须将全景图片链接到指定 LatLng 所在的确切位置。默认半径为 50 米。如果匹配区域中有多幅全景图片,API 将返回匹配度最高的全景图片。

如果您希望限制街景,以便仅查找室外全景图片,就可以使用来源。默认情况下,可以查看博物馆、公共建筑、咖啡馆和商家等室内地点的街景全景图片。请注意,指定位置可能不存在室外全景图片。

Java

LatLng sanFrancisco = new LatLng(37.754130, -122.447129);

// Set position with LatLng only.
streetViewPanorama.setPosition(sanFrancisco);

// Set position with LatLng and radius.
streetViewPanorama.setPosition(sanFrancisco, 20);

// Set position with LatLng and source.
streetViewPanorama.setPosition(sanFrancisco, StreetViewSource.OUTDOOR);

// Set position with LaLng, radius and source.
streetViewPanorama.setPosition(sanFrancisco, 20, StreetViewSource.OUTDOOR);
      

Kotlin

val sanFrancisco = LatLng(37.754130, -122.447129)

// Set position with LatLng only.
streetViewPanorama.setPosition(sanFrancisco)

// Set position with LatLng and radius.
streetViewPanorama.setPosition(sanFrancisco, 20)

// Set position with LatLng and source.
streetViewPanorama.setPosition(sanFrancisco, StreetViewSource.OUTDOOR)

// Set position with LaLng, radius and source.
streetViewPanorama.setPosition(sanFrancisco, 20, StreetViewSource.OUTDOOR)
      

此外,您还可以通过向 StreetViewPanorama.setPosition() 传递 panoId,根据全景图片 ID 设置位置。

要检索相邻全景图片的全景图片 ID,请先使用 getLocation() 检索 StreetViewPanoramaLocation。该对象包含当前全景图片的 ID 和一个 StreetViewPanoramaLink 对象数组,其中的每个对象都包含与当前全景图片相关联的全景图片 ID。

Java

StreetViewPanoramaLocation location = streetViewPanorama.getLocation();
if (location != null && location.links != null) {
    streetViewPanorama.setPosition(location.links[0].panoId);
}
      

Kotlin

streetViewPanorama.location.links.firstOrNull()?.let { link: StreetViewPanoramaLink ->
    streetViewPanorama.setPosition(link.panoId)
}
      

放大和缩小

您可以通过设置 StreetViewPanoramaCamera.zoom 以程序化方式更改缩放级别。将缩放级别设置为 1.0 会将图片放大 2 倍。

下面这段代码使用 StreetViewPanoramaCamera.Builder() 构建一个新的相机,该相机具有现有相机的倾斜度和方位,但将缩放级别增加了 50%。

Java

float zoomBy = 0.5f;
StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder()
    .zoom(streetViewPanorama.getPanoramaCamera().zoom + zoomBy)
    .tilt(streetViewPanorama.getPanoramaCamera().tilt)
    .bearing(streetViewPanorama.getPanoramaCamera().bearing)
    .build();
      

Kotlin

val zoomBy = 0.5f
val camera = StreetViewPanoramaCamera.Builder()
    .zoom(streetViewPanorama.panoramaCamera.zoom + zoomBy)
    .tilt(streetViewPanorama.panoramaCamera.tilt)
    .bearing(streetViewPanorama.panoramaCamera.bearing)
    .build()
      

设置相机朝向(视角)

您可以通过在 StreetViewPanoramaCamera 上设置方位和倾斜度来确定街景相机的朝向。

方位
相机指向的方向,以与相机所在地周围正北方所呈顺时针角度表示。正北方为 0,东方为 90,南方为 180,西方为 270。
倾斜度
Y 轴上倾或下倾角度。范围是 -90 至 0 至 90,-90 为垂直俯视,0 为水平居中,90 为垂直仰视。方差的测量根据是相机的初始默认间距,该间距通常(但并不总是)水平间距。例如,在小山上拍摄的图片的默认间距多半不是水平间距。

下面这段代码使用 StreetViewPanoramaCamera.Builder() 构建一个新的相机,该相机具有现有相机的缩放级别和倾斜度,但将方位向左调整了 30 度。

Java

float panBy = 30;
StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder()
    .zoom(streetViewPanorama.getPanoramaCamera().zoom)
    .tilt(streetViewPanorama.getPanoramaCamera().tilt)
    .bearing(streetViewPanorama.getPanoramaCamera().bearing - panBy)
    .build();
      

Kotlin

val panBy = 30f
val camera = StreetViewPanoramaCamera.Builder()
    .zoom(streetViewPanorama.panoramaCamera.zoom)
    .tilt(streetViewPanorama.panoramaCamera.tilt)
    .bearing(streetViewPanorama.panoramaCamera.bearing - panBy)
    .build()
      

下面这段代码可使相机向上倾斜 30 度。

Java

float tilt = streetViewPanorama.getPanoramaCamera().tilt + 30;
tilt = (tilt > 90) ? 90 : tilt;

StreetViewPanoramaCamera previous = streetViewPanorama.getPanoramaCamera();

StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder(previous)
    .tilt(tilt)
    .build();
      

Kotlin

var tilt = streetViewPanorama.panoramaCamera.tilt + 30
tilt = if (tilt > 90) 90f else tilt
val previous = streetViewPanorama.panoramaCamera
val camera = StreetViewPanoramaCamera.Builder(previous)
    .tilt(tilt)
    .build()
      

为相机移动添加动画效果

要为相机移动添加动画效果,请调用 StreetViewPanorama.animateTo()。动画会在当前相机属性和新的相机属性之间插入。如果您想直接完成相机切换而不使用动画,可以将持续时间设置为 0。

Java

// Keeping the zoom and tilt. Animate bearing by 60 degrees in 1000 milliseconds.
long duration = 1000;
StreetViewPanoramaCamera camera =
    new StreetViewPanoramaCamera.Builder()
        .zoom(streetViewPanorama.getPanoramaCamera().zoom)
        .tilt(streetViewPanorama.getPanoramaCamera().tilt)
        .bearing(streetViewPanorama.getPanoramaCamera().bearing - 60)
        .build();
streetViewPanorama.animateTo(camera, duration);
      

Kotlin

// Keeping the zoom and tilt. Animate bearing by 60 degrees in 1000 milliseconds.
val duration: Long = 1000
val camera = StreetViewPanoramaCamera.Builder()
    .zoom(streetViewPanorama.panoramaCamera.zoom)
    .tilt(streetViewPanorama.panoramaCamera.tilt)
    .bearing(streetViewPanorama.panoramaCamera.bearing - 60)
    .build()
streetViewPanorama.animateTo(camera, duration)
      

下图显示了使用 Handler.postDelayed() 设定上述动画每 2000 毫秒运行一次的结果:

街景全景图片动画演示