Наложение фрагментов карты

Мозаичное наложение, иногда называемое мозаичным слоем, представляет собой набор изображений, отображаемых поверх фрагментов базовой карты.

Примеры кода

В репозитории ApiDemos на сайте GitHub доступен пример, где демонстрируется использование наложения:

Введение

Класс TileOverlay определяет набор изображений, отображаемых поверх фрагментов базовой карты.

Вам нужно предоставить фрагменты карты для каждого уровня масштабирования, который вы хотите поддерживать. Если у вас достаточно фрагментов карты на нескольких уровнях масштабирования, вы можете дополнить геоданные Google для всей карты.

Мозаичные наложения используются, когда нужно добавить к карте большое количество изображений (как правило, для покрытия значительных географических областей). Наземные наложения используются в случаях, когда необходимо закрепить отдельное изображение на одном участке карты.

Вы также можете накладывать прозрачные фрагменты, чтобы добавлять на карту дополнительные объекты. Для этого можно использовать прозрачные изображения или задавать коэффициент прозрачности фрагмента программным образом.

Координаты фрагментов и уровни масштабирования

Google Maps API разбивает изображения на каждом уровне масштабирования на набор квадратных фрагментов карты, расположенных в виде сетки. Когда карта перемещается к новому местоположению или изменяется уровень масштабирования, Maps API определяет необходимые фрагменты и создает список фрагментов, которые нужно получить.

Фрагмент с координатами (0,0) всегда находится в северо-западном углу карты, при этом значения X увеличиваются в направлении с запада на восток, а значения Y увеличиваются в направлении с севера на юг. Фрагменты индексируются с использованием координат X, Y относительно исходной точки.

На уровне масштабирования 0 карта всего мира отображается как один фрагмент. На каждом уровне масштабирования выполняется увеличение с коэффициентом 2. Следовательно, на уровне масштабирования 1 карта будет отображаться в виде сетки фрагментов 2 x 2. На уровне масштабирования 2 это будет сетка 4 x 4. На уровне масштабирования 3 это будет сетка 8 x 8 и так далее.

Например, на уровне масштабирования 2 земная поверхность делится на 16 фрагментов. Каждый фрагмент можно описать с помощью уникальной комбинации координат X, Y и масштаба:

При создании изображений для мозаичного слоя вам потребуется создать по одному изображению для каждого фрагмента на каждом уровне масштабирования, который вы хотите поддерживать. В Google Картах при отображении фрагментов используется размер 256 dp (аппаратно-независимых пикселей). Для устройств с экранами высокого разрешения рекомендуется использовать фрагменты с большим значением dpi (512 x 512 пикселей). Дополнительные сведения о поддержке экранов с различными размерами и плотностью пикселей приведены в документации для разработчиков Android.

Примечание. Уровни масштабирования, поддерживаемые камерой, зависят от различных факторов и не имеют отношения к уровням, которые будут поддерживаться вашими фрагментами.

  1. GoogleMap.getMaxZoomLevel() возвращает максимальный уровень масштабирования, доступный при текущем положении камеры. При этом учитывается используемый тип карты. Например, у спутниковых карт или карт рельефа может быть меньший максимальный уровень масштабирования, чем у фрагментов базовых карт.
  2. GoogleMap.getMinZoomLevel() возвращает минимальный уровень масштабирования, который будет одинаковым для каждого места (в отличие от максимального уровня), но может различаться в зависимости от используемых устройств и размеров карт.

Как добавить накладываемый фрагмент карты

Самый простой и распространенный способ создания мозаичного наложения – указать URL-адрес соответствующего изображения фрагмента. UrlTileProvider – частичная реализация класса TileProvider, позволяющая указывать фрагменты изображений с помощью URL. При использовании этого класса необходимо, чтобы у всех изображений были одинаковые размеры.

Вам потребуется реализовать метод UrlTileProvider.getTileUrl(), который принимает координаты фрагмента (X, Y, масштаб) и возвращает URL изображения, которое будет использовано для этого фрагмента карты. Этот метод должен возвращать значение null, если для указанных координат X, Y и масштаба нет соответствующего фрагмента. URL может указывать на веб-ресурс, ресурс Android или файл на локальном диске.

Создайте комплект изображений на сервере так, чтобы каждому сочетанию координат X, Y и масштаба, которое вы хотите поддерживать, соответствовало определенное изображение фрагмента. Затем добавьте накладываемый фрагмент:

  1. Определите класс UrlTileProvider, который будет предоставлять изображения фрагментов.
  2. Переопределите метод getTileUrl() так, чтобы он создавал URL для каждого изображения фрагмента.
  3. Предоставьте объект TileOverlayOptions, содержащий параметры:
    • fadeIn: тип Boolean. Указывает, должны ли фрагменты появляться постепенно. Значение по умолчанию – true. Постепенное появление можно отключить, если переключение между мозаичными наложениями выполняется слишком быстро. Информация о связи между прозрачностью и постепенным появлением приведена в разделе Прозрачность далее в этой статье.
    • tileProvider: объект TileProvider, который будет использоваться для этого фрагмента.
    • transparency: тип Float. Устанавливает коэффициент прозрачности накладываемых изображений. Значение должно быть в диапазоне [0.0f, 1.0f]. 0.0f (значение по умолчанию) соответствует полной непрозрачности, а 1.0f – полной прозрачности. В разделе Прозрачность далее в этой статье приводится пример кода и описывается взаимосвязь между прозрачностью и постепенным появлением изображений.
    • visible: тип Boolean. Указывает, является ли накладываемый фрагмент карты видимым. Если фрагмент невидимый (значение false), он не отображается на карте, но сохраняет все остальные свойства. Значение по умолчанию – true.
    • zIndex: определяет порядок прорисовки мозаичного наложения относительно других наложений, включая наземные наложения, круги, ломаные линии и многоугольники. Наложения с более высокими значениями z-index прорисовываются выше наложений с меньшими значениями z-index. Порядок наложений с одинаковыми значениями z-index будет произвольным. По умолчанию z-индекс равен 0. Обратите внимание, что маркеры всегда располагаются поверх всех остальных наложений (независимо от значений z-индекса для этих наложений).
  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, посмотрите реализацию TileOverlayDemoActivity в примере кода, прилагаемом к SDK сервисов Google Play.

Как настроить прозрачность накладываемых фрагментов карты

Прозрачные мозаичные наложения на карте применяются для того, чтобы пользователи могли видеть исходную карту под наложенными фрагментами. Для этого можно использовать собственные прозрачные фрагменты или установить коэффициент прозрачности мозаичных наложений программным образом.

В следующем примере кода показано, как изменить значение прозрачности с 0.5f на 0.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
    }
}
      

Прозрачность реализуется как множитель альфа-канала для изображений фрагментов. Чтобы задать прозрачность накладываемого фрагмента, предоставьте объект TileOverlayOptions, где поле transparency имеет значение в диапазоне [0.0f, 1.0f], как показано в примере выше. При значении 0.0f фрагмент полностью непрозрачен, а при значении 1.0f – полностью прозрачен. Значение по умолчанию – 0.0f (полная непрозрачность).

Получить значение прозрачности можно с помощью метода TileOverlay.getTransparency(), а изменить это значение – с помощью метода TileOverlay.setTransparency().

Прозрачность, анимация и постепенное появление

При изменении прозрачности анимация не применяется. Параметр прозрачности используется вместе с параметром fadeIn.

Параметр Fade-in отвечает за анимацию прозрачности при загрузке фрагмента. Если установить значение прозрачности, фрагменты будут появляться постепенно – от полной прозрачности до ее установленного значения. Если изменить прозрачность во время постепенного появления, анимация будет продолжаться до нового заданного значения прозрачности.

Как удалить накладываемый фрагмент карты

Удалить накладываемый фрагмент карты можно с помощью метода TileOverlay.remove().

Java

tileOverlay.remove();
      

Kotlin

tileOverlay.remove()
      

Как удалить устаревшие фрагменты

Если фрагменты, используемые в мозаичном наложении, "устаревают", их можно обновить, вызвав метод clearTileCache(). В результате все фрагменты в этом наложении будут перезагружены. Например, если фрагменты, предоставленные с помощью TileProvider, изменились, нужно вызвать метод clearTileCache(), чтобы прежние фрагменты не отображались.

Java

tileOverlay.clearTileCache();
      

Kotlin

tileOverlay.clearTileCache()