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

Наложение фрагментов карты – это набор изображений, которые показываются поверх фрагментов базовой карты.

Примеры кода

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

Введение

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

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

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

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

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

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

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

На уровне масштабирования 0 карта всего мира отображается как один фрагмент. На каждом следующем уровне масштаб увеличивается вдвое. Следовательно, на первом уровне масштабирования карта будет отображаться в виде сетки фрагментов 2 x 2, на втором – 4 x 4, на третьем – 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: логическое значение. Указывает, должны ли фрагменты появляться постепенно. Значение по умолчанию – true. Если переключение между фрагментами выполняется слишком быстро, для этого параметра можно задать значение false. Информация о связи между прозрачностью и постепенным появлением приведена в разделе Как настроить прозрачность накладываемых фрагментов карты далее в этой статье.
    • tileProvider: объект TileProvider, который будет использоваться для этого фрагмента.
    • transparency: число с плавающей запятой. Устанавливает коэффициент прозрачности накладываемых изображений. Значение должно быть в диапазоне [0.0f, 1.0f]. 0.0f (значение по умолчанию) соответствует полной непрозрачности, а 1.0f – полной прозрачности. В разделе Как настроить прозрачность накладываемых фрагментов карты далее в этой статье приводится пример кода и описывается взаимосвязь между прозрачностью и постепенным появлением изображений.
    • visible: логическое значение. Указывает, является ли накладываемый фрагмент карты видимым. Если фрагмент невидимый (значение false), он не показывается на карте, но сохраняет все остальные свойства. Значение по умолчанию – true.
    • zIndex: определяет порядок прорисовки фрагментов карты относительно других наложений, включая наземные наложения, круги, ломаные линии и многоугольники. Чем больше значение этого параметра, тем выше по оси Z находится наложение, и наоборот. Порядок наложений с одинаковыми значениями z-индекса будет произвольным. По умолчанию 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.

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

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

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

Java


tileOverlay.remove();

      

Kotlin


tileOverlay?.remove()

      

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

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

Java


tileOverlay.clearTileCache();

      

Kotlin


tileOverlay?.clearTileCache()