图块叠加层

图块叠加层有时称作图块图层,是显示在基本地图图块之上的图片集。

代码示例

GitHub 上的 ApiDemos 代码库包含一个演示如何使用图块叠加层地图项的示例:

简介

TileOverlay 定义在基本地图图块之上添加的一组图片。

您需要为您想支持的每个缩放级别提供图块。如果您在多个缩放级别都有足够的图块,便可为整个地图补充 Google 的地图数据。

如果您要为地图添加大量图像(通常覆盖大片地域),就需要使用图块叠加层。相反,如果您想将单个图片固定在地图上的某一区域,便可使用地面叠加层

您也可以在图块叠加层上以编程方式设置透明度系数或者提供透明图块图片,使用透明的图块叠加层向地图添加更多地图项。

图块坐标和缩放级别

Google Maps API 将各缩放级别的图像分解成一组以网格形式排列的方形地图图块。当地图移至新位置,或者切换到新的缩放级别时,Maps API 会确定需要哪些图块,并将该信息转换为需要检索的一组图块。

坐标为 (0,0) 的图块始终位于地图的西北角,x 值从西向东增加,y 值从北向南增加。利用基于该原点的 (x,y) 坐标为图块建立索引。

缩放级别为 0 时,整个世界使用单个图块渲染。缩放级别每增加 1,放大为原来的 2 倍。因此,缩放级别为 1 时,地图将渲染为一个 2x2 图块网格。缩放级别为 2 时,渲染为 4x4 网格。缩放级别为 3 时,渲染为 8x8 网格,依此类推。

例如,缩放级别为 2 时,地球分成 16 个图块。每个图块都可通过唯一的 (x, y) 和缩放级别组合进行引用:

为图块图层创建图片时,您需要为您想支持的每个缩放级别下的每个图块都创建一个图片。Google 地图以 256dp(设备无关像素)为目标显示图块。对于高分辨率设备,建议返回高 dpi 图块(512x512 像素)。请参阅 Android 开发者文档,了解有关如何支持不同屏幕尺寸和密度的信息。

注意:相机支持的缩放级别取决于各种因素,与您的图块支持的缩放级别无关。

  1. GoogleMap.getMaxZoomLevel() 返回当前相机位置可实现的最大缩放级别。这会考虑当前正在使用的地图类型。例如,卫星地图或地形地图图块的最大缩放级别可能低于基本地图图块。
  2. GoogleMap.getMinZoomLevel() 返回最小缩放级别,每个位置的最小缩放级别都是一样的(这与最大缩放级别不同),但不同设备和地图尺寸之间可能有所差异。

添加图块叠加层

最简单也是最常见的图块叠加层创建方法是,提供指向相关图块图片的网址。UrlTileProviderTileProvider 的部分实现,基于网址提供图片图块。该类要求所有图片都具有相同的尺寸。

您需要实现 UrlTileProvider.getTileUrl(),它接受图块坐标 (x, y, 缩放级别),并且返回的网址指向用于图块的图片。如果给定 (x, y) 和缩放级别没有对应的图块,该方法应返回空值。网址可指向网络资源、Android 资源或本地磁盘上的文件。

在服务器上建立您的图块图片库,您需要为您打算支持的所有 (x,y) 坐标和缩放级别定义相应的图块图片。然后添加图块叠加层:

  1. 定义用于提供图块图片的 UrlTileProvider
  2. 重写 getTileUrl() 以构建每个图块图片的网址。
  3. 提供带有相关选项的 TileOverlayOptions 对象:
    • fadeIn:布尔值。指定图块是否应淡入。默认值为 true。您可能会发现,关闭淡入有助于在图块叠加层间快速切换。如需了解透明度和淡入之间的关系,请参阅下面的透明度部分。
    • tileProvider:用于此叠加层的 TileProvider
    • transparency:浮点数。设置图块图片的透明度系数。该值必须在 [0.0f, 1.0f] 范围内,其中 0.0f 表示完全不透明(默认),1.0f 表示完全透明。请在下面的透明度部分查看代码示例并了解透明度与淡入之间的关系。
    • visible:布尔值。指定图块叠加层的可见性。不可见的图块叠加层(值为 false)不会绘制在地图上,但会保持其所有其他属性。默认值为 true
    • zIndex:确定图块叠加层相对于其他叠加层的绘制顺序,其他叠加层包括地面叠加层圆形、多段线以及多边形。z-index 较高的叠加层绘制在 z-index 较低的叠加层之上。z-index 相同的叠加层可按任意顺序绘制。默认 z-index 为 0。请注意,无论其他叠加层的 z-index 如何,标记始终在其他叠加层之上绘制。
  4. 调用 GoogleMap.addTileOverlay() 以将叠加层添加到地图中。

Java


private GoogleMap map;

TileProvider tileProvider = new UrlTileProvider(256, 256) {

    @Override
    public URL getTileUrl(int x, int y, int zoom) {

        /* Define the URL pattern for the tile images */
        String s = String.format("http://my.image.server/images/%d/%d/%d.png", zoom, x, y);

        if (!checkTileExists(x, y, zoom)) {
            return null;
        }

        try {
            return new URL(s);
        } catch (MalformedURLException e) {
            throw new AssertionError(e);
        }
    }

    /*
     * Check that the tile server supports the requested x, y and zoom.
     * Complete this stub according to the tile range you support.
     * If you support a limited range of tiles at different zoom levels, then you
     * need to define the supported x, y range at each zoom level.
     */
    private boolean checkTileExists(int x, int y, int zoom) {
        int minZoom = 12;
        int maxZoom = 16;

        return (zoom >= minZoom && zoom <= maxZoom);
    }
};

TileOverlay tileOverlay = map.addTileOverlay(new TileOverlayOptions()
    .tileProvider(tileProvider));

      

Kotlin


private lateinit var map: GoogleMap

var tileProvider: TileProvider = object : UrlTileProvider(256, 256) {
    override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {

        /* Define the URL pattern for the tile images */
        val url = "http://my.image.server/images/$zoom/$x/$y.png"
        return if (!checkTileExists(x, y, zoom)) {
            null
        } else try {
            URL(url)
        } catch (e: MalformedURLException) {
            throw AssertionError(e)
        }
    }

    /*
     * Check that the tile server supports the requested x, y and zoom.
     * Complete this stub according to the tile range you support.
     * If you support a limited range of tiles at different zoom levels, then you
     * need to define the supported x, y range at each zoom level.
     */
    private fun checkTileExists(x: Int, y: Int, zoom: Int): Boolean {
        val minZoom = 12
        val maxZoom = 16
        return zoom in minZoom..maxZoom
    }
}

val tileOverlay = map.addTileOverlay(
    TileOverlayOptions()
        .tileProvider(tileProvider)
)

      

如需查看 UrlTileProvider 的实际应用示例,请参阅 Google Play 服务 SDK 附带示例代码中的 TileOverlayDemoActivity

设置图块叠加层的透明度

在地图上叠加透明图块很有用,这样用户就可以看到叠加的图块下面的基础地图。您可以通过提供自己的透明图块或以编程方式在图块叠加层上设置透明度系数来执行这一操作。

下面的代码示例可以在 0.5f0.0f 之间切换图块叠加层的透明度:

Java


private TileOverlay tileOverlayTransparent;

@Override
public void onMapReady(GoogleMap map) {
    tileOverlayTransparent = map.addTileOverlay(new TileOverlayOptions()
        .tileProvider(new UrlTileProvider(256, 256) {
            // ...
        })
        .transparency(0.5f));
}

// Switch between 0.0f and 0.5f transparency.
public void toggleTileOverlayTransparency() {
    if (tileOverlayTransparent != null) {
        tileOverlayTransparent.setTransparency(0.5f - tileOverlayTransparent.getTransparency());
    }
}

      

Kotlin


private var tileOverlayTransparent: TileOverlay? = null

override fun onMapReady(map: GoogleMap) {
    tileOverlayTransparent = map.addTileOverlay(
        TileOverlayOptions()
            .tileProvider(object : UrlTileProvider(256, 256) {
                // ...
            })
            .transparency(0.5f)
    )
}

// Switch between 0.0f and 0.5f transparency.
fun toggleTileOverlayTransparency() {
    tileOverlayTransparent?.let {
        it.transparency = 0.5f - it.transparency
    }
}

      

透明度作为图块图片的 Alpha 通道倍增值来实现。要设置图块叠加层的透明度,需要提供一个 TileOverlayOptions 对象,其中 transparency 应位于 [0.0f, 1.0f] 的范围内,如上文示例所示。值为 0.0f 表示图块叠加层完全不透明,1.0f 表示完全透明。默认值为 0.0f(不透明)。

您可以通过调用 TileOverlay.getTransparency() 获取图块叠加层的透明度,并且可以通过调用 TileOverlay.setTransparency() 对其进行更改。

透明度、动画和淡入

更改透明度时没有动画。透明度选项搭配 fadeIn 选项使用。

淡入会在加载图块时提供透明度动画。如果您设置透明度值,图块将从完全透明淡入到定义的透明度值。如果您在淡入期间更改透明度,动画会继续淡入,直至实现新的目标透明度设置为止。

移除图块叠加层

您可以使用 TileOverlay.remove() 方法移除图块叠加层。

Java


tileOverlay.remove();

      

Kotlin


tileOverlay?.remove()

      

清除过时图块

如果图块叠加层提供的图块变得“过时”,您可以调用 clearTileCache() 强制刷新。这会使该叠加层上的所有图块重新加载。例如,如果 TileProvider 提供的图块发生变化,您必须在之后调用 clearTileCache(),以确保不再渲染旧图块。

Java


tileOverlay.clearTileCache();

      

Kotlin


tileOverlay?.clearTileCache()