Подтвердить что ты не робот

Android Google Maps - пользовательский фон за всеми маркерами

Я пытаюсь установить фон между картой и моим маркером; это изображение должно всегда (!) оставаться за всеми маркерами.

Я попробовал несколько способов, например. showInfoWindow() на всех моих маркерах, кроме фонового изображения, но похоже, что это поможет только для последнего.

Затем я попробовал решение с помощью GroundOverlay, но мне нужно, чтобы мое изображение всегда оставалось того же размера (например, половину размера устройства), независимо от коэффициента масштабирования.

Есть ли решение для Android?

4b9b3361

Ответ 1

Это легко сделать.

Добавьте два маркера вместо одного. Сначала добавьте фон как растровое изображение в lat_lng.

Что-то вроде этого:

map.addMarker(new MarkerOptions()
      .position(lat_lng)
      .anchor(0.5f, 0.5f)
      .icon(BitmapDescriptorFactory.fromBitmap(bitmap)));

Затем добавьте маркер, как обычно, с тем же lat_lng.

Сделайте выше для каждого из ваших маркеров.

Ответ 2

Вы можете попробовать это, рассчитать размеры в соответствии с коэффициентом масштабирования и применить эти измерения к GroundOverlay.

float zoomLevel=mMap.getCameraPosition().zoom;
    //calculate meters*********************         
    myBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
    myCenter=  mMap.getCameraPosition().target;
    if (myCenter.latitude==0 || myCenter.longitude==0) {
        myCenter=new LatLng(myLocation.getLatitude(),myLocation.getLongitude());
    }

    LatLng ne = myBounds.northeast;

    // r = radius of the earth in statute miles
    double r = 3963.0;  

    // Convert lat or lng from decimal degrees into radians (divide by 57.2958)
    double lat1 = myCenter.latitude / 57.2958; 
    double lon1 = myCenter.longitude / 57.2958;
    final double lat2 = ne.latitude / 57.2958;
    final double lon2 = ne.longitude / 57.2958;

    // distance = circle radius from center to Northeast corner of bounds
    double dis = r * Math.acos(Math.sin(lat1) * Math.sin(lat2) + 
      Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1));

    //1 Meter = 0.000621371192237334 Miles
    double meters_calc=dis/0.000621371192237334;

    float factor=1;  
    if (zoomLevel==15) {  // my default zoom level yours can be different
        metersoverlay=meters_calc;  // global variable metersoverlay set
    }
    else { // if my zoom level change then I have to calculate dimension scale factor
        factor=(float) (meters_calc/metersoverlay); 
    }

    //******************************* now we are ready to set dimension of background overlay
    float dimensions=1000*factor; 
    loadingGroundOverlayBg.setDimensions(dimensions);

Ответ 3

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

Из документация:

Позиция

Существует два способа задания положения наложения на землю:

  • Использование местоположения: вы должны предоставить изображение наземного наложения, LatLng, на который будет закреплен якорь, и ширину наложения (в метрах). Якорь по умолчанию составляет 50% от верхней части изображения и 50% слева от изображения. Это можно изменить. Вы можете дополнительно указать высоту наложения (в метрах). Если вы не обеспечиваете высоту наложения, он будет автоматически рассчитан для сохранения пропорций изображения.

  • Использование границ: вы должны предоставить LatLngBounds, который будет содержать изображение.

В следующем примере используется OnCameraChangeListener для удаления и добавления GroundOverlay, который отображает ic_launcher, который можно извлечь в центре карты, 75% от ширины карты (удаление и добавление GroundOverlay на событие onCameraChange гарантирует, что размер вашего изображения всегда один и тот же независимо от уровня масштабирования).

public class MyMapActivity extends Activity implements OnCameraChangeListener {
    GroundOverlay backgroundOverlay = null;
    GoogleMap map;

    // ...

    @Override
    public void onCameraChange(final CameraPosition cameraPosition) {
        if (backgroundOverlay != null) {
            backgroundOverlay.remove();
        }

        VisibleRegion visibleRegion = map.getProjection()
                .getVisibleRegion();

        Location nearLeftLocation = new Location("nearLeftLocation");
        nearLeftLocation.setLatitude(visibleRegion.nearLeft.latitude);
        nearLeftLocation.setLongitude(visibleRegion.nearLeft.longitude);

        Location nearRightLocation = new Location("nearRightLocation");
        nearRightLocation.setLatitude(visibleRegion.nearRight.latitude);
        nearRightLocation.setLongitude(visibleRegion.nearRight.longitude);

        float width = nearLeftLocation.distanceTo(nearRightLocation);

        GroundOverlayOptions background = new GroundOverlayOptions()
                .image(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher))
                .position(cameraPosition.target, width * 0.75f);

        backgroundOverlay = map.addGroundOverlay(background);
    }
}

UPDATE:

Как я уже сказал в комментариях, мы можем setPosition и setDimensions в существующем GroundOverlay вместо добавления/удаления его при каждом изменении камеры.

Я тестировал его на нескольких устройствах и, похоже, уменьшал мерцание на низкоуровневых устройствах, но все же не идеальное решение (изменение изображения между масштабированием). Я уверен, что это лучшее, что мы можем использовать GroundOverlay s.

public class MyMapActivity extends Activity implements OnCameraChangeListener {
    GroundOverlay backgroundOverlay = null;
    GoogleMap map;

    // ...

    @Override
    public void onCameraChange(final CameraPosition cameraPosition) {
        VisibleRegion visibleRegion = map.getProjection().getVisibleRegion();

        Location nearLeftLocation = new Location("nearLeftLocation");
        nearLeftLocation.setLatitude(visibleRegion.nearLeft.latitude);
        nearLeftLocation.setLongitude(visibleRegion.nearLeft.longitude);

        Location nearRightLocation = new Location("nearRightLocation");
        nearRightLocation.setLatitude(visibleRegion.nearRight.latitude);
        nearRightLocation.setLongitude(visibleRegion.nearRight.longitude);

        float width = nearLeftLocation.distanceTo(nearRightLocation);

        if (backgroundOverlay == null) {
            GroundOverlayOptions background = new GroundOverlayOptions()
                    .image(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher))
                    .position(cameraPosition.target, width * 0.75f);

            backgroundOverlay = map.addGroundOverlay(background);
        } else {
            backgroundOverlay.setPosition(cameraPosition.target);
            backgroundOverlay.setDimensions(width * 0.75f);
        }
    }
}

UPDATE

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

Идея заключается в создании TileProvider, который возвращает всегда очень маленькое (2x2 пикселя в моем примере) изображение, которое будет рисоваться ниже всех ваших маркеров. Чтобы обеспечить производительность, Tile, возвращаемый TileProvider, всегда будет одним и тем же.

Вот код:

public class BackgroundTileProvider implements TileProvider {
    private Tile tile;

    @Override
    public Tile getTile(int x, int y, int zoom) {
        if (tile == null) {
            // Create a very small (for performance) bitmap with alpha
            Bitmap bmp = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);

            // Draw the desired color to use as background
            Canvas canvas = new Canvas(bmp);
            canvas.drawColor(Color.argb(150, 255, 0, 0));

            // Get the bytes and create the Tile
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);

            tile = new Tile(2, 2, stream.toByteArray());
        }

        return tile;
    }
}

Вам нужно будет добавить TileOverlay на свою карту следующим образом:

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

Результат будет выглядеть следующим образом:

введите описание изображения здесь