Android карта v2 увеличить, чтобы показать все маркеры


286

У меня есть 10 маркеров в GoogleMap. Я хочу максимально увеличить масштаб изображения и оставить все маркеры на виду? В более ранней версии этого можно добиться, zoomToSpan()но в v2 я понятия не имею, как это сделать. Далее я знаю радиус круга, который должен быть виден.

Ответы:


810

Вы должны использовать CameraUpdate класс для выполнения (возможно) всех программных перемещений карты.

Для этого сначала вычислите границы всех маркеров следующим образом:

LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker marker : markers) {
    builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();

Затем получите объект описания движения, используя фабрику CameraUpdateFactory:

int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);

Наконец, переместите карту:

googleMap.moveCamera(cu);

Или, если вы хотите анимацию:

googleMap.animateCamera(cu);

Вот и все :)

Пояснение 1

Почти все методы перемещения требуют, чтобы Mapобъект прошел процесс макета. Вы можете подождать, пока это произойдет, используя addOnGlobalLayoutListenerконструкцию. Подробности можно найти в комментариях к этому ответу и оставшихся ответах. Вы также можете найти полный код для установки экстента карты, используя addOnGlobalLayoutListenerздесь .

Пояснение 2

В одном комментарии отмечается, что использование этого метода только для одного маркера приводит к тому, что масштаб карты устанавливается на «странный» уровень масштабирования (который, я считаю, является максимальным уровнем масштабирования, доступным для данного местоположения). Я думаю, что это ожидается, потому что:

  1. LatLngBounds boundsЭкземпляр будет иметь northeastсвойство , равное southwest, а это означает , что часть площади земли , покрытой этим boundsточно равна нулю. (Это логично, поскольку у одного маркера нет области.)
  2. Пропустив boundsк CameraUpdateFactory.newLatLngBoundsвам по существу запроса вычисления такого уровня , что зум - bounds(имеющей нулевую площадь) будет охватывать весь вид на карту.
  3. Вы действительно можете выполнить этот расчет на листе бумаги. Теоретический уровень масштабирования, который является ответом, равен + ∞ (положительная бесконечность). На практике Mapобъект не поддерживает это значение, поэтому он привязан к более разумному максимальному уровню, разрешенному для данного местоположения.

Другой способ выразить это: как Mapобъект может знать, какой уровень масштабирования следует выбрать для одного местоположения ? Возможно, оптимальным значением должно быть 20 (если оно представляет конкретный адрес). Или, может быть, 11 (если он представляет город). Или, может быть, 6 (если он представляет страну). API не такой умный, и решение за вами.

Итак, вы должны просто проверить, markersимеет ли только одно местоположение, и если это так, используйте одно из:

  • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - перейти в положение маркера, оставить текущий уровень масштабирования без изменений.
  • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - перейти в положение маркера, установить уровень масштабирования на произвольно выбранное значение 12.

21
Следует отметить, что перемещение не может происходить из вызовов onCreate, представление должно быть создано. Мне нужно было использовать addOnGlobalLayoutListener, чтобы получить соответствующий образец.
Барух Эвен

6
@ Бар Хорошо, это отчасти правда. Если быть точным: некоторые методы перемещения не будут работать сразу после создания объекта карты. Причиной этого является то, что объект карты еще не измерен, т.е. он не прошел процесс макета. Типичным решением является использование addOnGlobalLayoutListener()или post()с соответствующим Runnable. Именно поэтому невозможно получить координаты экрана маркера onCreate- см. Stackoverflow.com/q/14429877/1820695 Однако вы можете использовать некоторые методы даже до того, как разметка произошла - например. CameraUpdateFactory.newLatLngBounds()с 4 парам .
Andr

1
Чувак, ты спас мой день ... на самом деле пытался сделать это самостоятельно, вычислять границы вручную и масштабировать, пока маркер в нем ... работал довольно уродливо, но с твоим простым методом это работает как шарм. Спасибо
Bibu

9
googleMap .setOnMapLoadedCallback (new GoogleMap.OnMapLoadedCallback () {@Override public void onMapLoaded () {googleMap.moveCamera (cu);}}); Это позволит избежать ошибки по мере.
Рамз

1
это работает иначе, но когда на карте есть один маркер, он приближается к некоторому странному уровню, на котором карта становится размытой. Как это исправить?
Утсав Гупта

124

Google Map V2

Следующее решение работает для Android Marshmallow 6 (API 23, API 24, API 25, API 26, API 27, API 28). Это также работает в Xamarin.

LatLngBounds.Builder builder = new LatLngBounds.Builder();

//the include method will calculate the min and max bound.
builder.include(marker1.getPosition());
builder.include(marker2.getPosition());
builder.include(marker3.getPosition());
builder.include(marker4.getPosition());

LatLngBounds bounds = builder.build();

int width = getResources().getDisplayMetrics().widthPixels;
int height = getResources().getDisplayMetrics().heightPixels;
int padding = (int) (width * 0.10); // offset from edges of the map 10% of screen

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding);

mMap.animateCamera(cu);

7
Для лучшего внешнего вида используйте высоту вместо ширины и берите 20% вместо 10%.
нуб

2
Принятый ответ иногда вызывает странное увеличение. Это работает как шарм. Это лучший ответ.
Hüseyin Bülbül

1
Этот ответ работает лучше, чем принятый, принятый вызывает утомительное поведение.
Хайтам

13

Так

Мне нужно было использовать addOnGlobalLayoutListener, чтобы получить соответствующий образец

например, ваша карта Google находится внутри RelativeLayout:

RelativeLayout mapLayout = (RelativeLayout)findViewById(R.id.map_layout);
mapLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //and write code, which you can see in answer above
        }
    });

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

13

Я не мог использовать onGlobalLayoutlistener, поэтому вот еще одно решение для предотвращения "Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions."ошибки:

mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { 
@Override 
public void onMapLoaded() { 
    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
 } 
});

Этот снимок занимает намного больше времени, чем OnGlobalLayoutListener, поэтому для меня он по-прежнему сначала отображал область / масштаб карты по умолчанию, прежде чем перемещать камеру в соответствии с моими потребностями
до

Как дать отступы, так как мои 2 маркера касаются границ карты.
Пратик Бутани

9

Работает нормально для меня.

Из этого кода я отображаю несколько маркеров с определенным увеличением на экране карты.

// Объявленные переменные

private LatLngBounds bounds;
private LatLngBounds.Builder builder;

// Метод добавления нескольких точек маркера с помощью нарисованного значка

private void drawMarker(LatLng point, String text) {

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(point).title(text).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon));
        mMap.addMarker(markerOptions);
        builder.include(markerOptions.getPosition());

    }

// Для добавления нескольких маркеров, видимых на карте

@Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        builder = new LatLngBounds.Builder();
    for (int i = 0; i < locationList.size(); i++) {

        drawMarker(new LatLng(Double.parseDouble(locationList.get(i).getLatitude()), Double.parseDouble(locationList.get(i).getLongitude())), locationList.get(i).getNo());

     }
     bounds = builder.build();
     CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 0);
     mMap.animateCamera(cu);

4

Примечание. Это не решение исходного вопроса. Это решение одной из подзадач, обсужденных выше .

Решение для @andr Clarification 2 -

Это действительно проблематично, когда в границах есть только один маркер, и из-за этого уровень масштабирования установлен на очень высокий уровень ( уровень 21 ). И Google не предоставляет никакого способа установить максимальный уровень масштабирования в этой точке. Это также может произойти, когда есть более 1 маркера, но все они довольно близко друг к другу. Тогда также возникнет та же проблема.

Решение - Предположим, вы хотите, чтобы ваша Карта никогда не превышала 16-кратный уровень масштабирования. Затем после выполнения -

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
mMap.moveCamera(cu);

Проверьте, не превысил ли ваш уровень масштабирования уровень 16 (или что вы хотите) -

float currentZoom = mMap.getCameraPosition().zoom;

И если этот уровень больше 16, что будет только в том случае, если маркеров очень мало или все маркеры расположены очень близко друг к другу, просто уменьшите масштаб карты в этой конкретной позиции, установив уровень масштабирования 16.

mMap.moveCamera(CameraUpdateFactory.zoomTo(16));

Таким образом, у вас никогда не возникнет проблема «странного» уровня масштабирования, который также очень хорошо объясняется @andr.


хорошее решение, но если вы поместите объект "cu" внутрь onMapReady (), тогда в этом случае будет неправильное поведение: полученное местоположение -> увеличение велико, поэтому сделайте его 16 -> затем пользователь увеличит -> полученное местоположение снова, и камера будет вернуть на уровень 16 . Это может быть проблемой, когда местоположение принимается практически в режиме реального времени, поскольку оно будет продолжать возвращаться к уровню 16.
Махер Набиль

«И Google не предоставляет никакого способа установить максимальный уровень масштабирования на данный момент». - Неверно: developers.google.com/android/reference/com/google/android/gms/…
user1209216

3

это поможет .. из демо Google Apis

private List<Marker> markerList = new ArrayList<>();
Marker marker = mGoogleMap.addMarker(new MarkerOptions().position(geoLatLng)
                .title(title));
markerList.add(marker);
    // Pan to see all markers in view.
    // Cannot zoom to bounds until the map has a size.
    final View mapView = getSupportFragmentManager().findFragmentById(R.id.map).getView();
    if (mapView!=null) {
        if (mapView.getViewTreeObserver().isAlive()) {
            mapView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @SuppressWarnings("deprecation") // We use the new method when supported
                @SuppressLint("NewApi") // We check which build version we are using.
                @Override
                public void onGlobalLayout() {
                    //Calculate the markers to get their position
                    LatLngBounds.Builder b = new LatLngBounds.Builder();
                    for (Marker m : markerList) {
                        b.include(m.getPosition());
                    }
                    // also include current location to include in the view
                    b.include(new LatLng(mLocation.getLatitude(),mLocation.getLongitude()));

                    LatLngBounds bounds = b.build();
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                    mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
                }
            });
        }
    }

для ясной информации посмотрите на этот URL. https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java



1

Показать все маркеры на карте Google

В этих методах хранить все маркеры и автоматически масштабировать, чтобы показать все маркеры на карте Google.

// Declare the Markers List.
List<MarkerOptions> markerList;
private BitmapDescriptor vnrPoint,banPoint;


public void storeAllMarkers()
{
      markerList=new ArrayList<>();
      markerList.removeAll(markerList);


      // latitude and longitude of Virudhunagar

      double latitude1=9.587209;
      double longitude1=77.951431;
   vnrPoint=BitmapDescriptorFactory.fromResource(R.drawable.location_icon_1);
      LatLng vnr = new LatLng(latitude1, longitude1);
      MarkerOptions vnrMarker = new MarkerOptions();
      vnrMarker.position(vnr);
      vnrMarker.icon(vnrPoint);
      markerList.add(vnrMarker);

      // latitude and longitude of Bengaluru

      double latitude2=12.972442;
      double longitude2=77.580643;

    banPoint=BitmapDescriptorFactory.fromResource(R.drawable.location_icon_2);

      LatLng ban = new LatLng(latitude2, longitude2);
      MarkerOptions bengalureMarker = new MarkerOptions();
      bengalureMarker.position(ban);
      bengalureMarker.icon(banPoint);
      markerList.add(bengalureMarker);

      // You can add any numbers of MarkerOptions like this.

     showAllMarkers();

 }


public void showAllMarkers()
{
    LatLngBounds.Builder builder = new LatLngBounds.Builder();

    for (MarkerOptions m : markerList) {
        builder.include(m.getPosition());
    }

    LatLngBounds bounds = builder.build();

    int width = getResources().getDisplayMetrics().widthPixels;
    int height = getResources().getDisplayMetrics().heightPixels;
    int padding = (int) (width * 0.30); 

    // Zoom and animate the google map to show all markers

    CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding);
    googleMap.animateCamera(cu);
}

0

Используйте метод "getCenterCoordinate", чтобы получить координату центра и использовать в CameraPosition.

private void setUpMap() {
    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setScrollGesturesEnabled(true);
    mMap.getUiSettings().setTiltGesturesEnabled(true);
    mMap.getUiSettings().setRotateGesturesEnabled(true);

    clientMarker = mMap.addMarker(new MarkerOptions()
            .position(new LatLng(Double.valueOf(-12.1024174), Double.valueOf(-77.0262274)))
            .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_taxi))
    );
    clientMarker = mMap.addMarker(new MarkerOptions()
            .position(new LatLng(Double.valueOf(-12.1024637), Double.valueOf(-77.0242617)))
            .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_location))
    );

    camPos = new CameraPosition.Builder()
            .target(getCenterCoordinate())
            .zoom(17)
            .build();
    camUpd3 = CameraUpdateFactory.newCameraPosition(camPos);
    mMap.animateCamera(camUpd3);
}


public LatLng getCenterCoordinate(){
    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    builder.include(new LatLng(Double.valueOf(-12.1024174), Double.valueOf(-77.0262274)));
    builder.include(new LatLng(Double.valueOf(-12.1024637), Double.valueOf(-77.0242617)));
    LatLngBounds bounds = builder.build();
    return bounds.getCenter();
}

0

У меня есть еще один способ сделать то же самое, что работает отлично. так что идея показать все маркеры на экране, нам нужен центр по длине и уровень масштабирования. вот функция, которая даст вам оба и потребует в качестве входных данных все объекты Latlng маркера.

 public Pair<LatLng, Integer> getCenterWithZoomLevel(LatLng... l) {
    float max = 0;

    if (l == null || l.length == 0) {
        return null;
    }
    LatLngBounds.Builder b = new LatLngBounds.Builder();
    for (int count = 0; count < l.length; count++) {
        if (l[count] == null) {
            continue;
        }
        b.include(l[count]);
    }

    LatLng center = b.build().getCenter();

    float distance = 0;
    for (int count = 0; count < l.length; count++) {
        if (l[count] == null) {
            continue;
        }
        distance = distance(center, l[count]);
        if (distance > max) {
            max = distance;
        }
    }

    double scale = max / 1000;
    int zoom = ((int) (16 - Math.log(scale) / Math.log(2)));
    return new Pair<LatLng, Integer>(center, zoom);
}

Эта функция возвращает объект Pair, который вы можете использовать как

Pair pair = getCenterWithZoomLevel (l1, l2, l3 ..); mGoogleMap.moveCamera (CameraUpdateFactory.newLatLngZoom (pair.first, pair.second));

Вы можете вместо того, чтобы использовать отступы, чтобы убрать маркеры от границ экрана, вы можете настроить масштабирование на -1.


-3
   //For adding a marker in Google map
        MarkerOptions mp = new MarkerOptions();
        mp.position(new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude)));
        mp.snippet(strAddress);
        map.addMarker(mp);

        try {

            b = new LatLngBounds.Builder();

            if (MapDetailsList.list != null && MapDetailsList.list.size() > 0) {

                for (int i = 0; i < MapDetailsList.list.size(); i++) {

                    b.include(new LatLng(Double.parseDouble(MapDetailsList.list.get(i).getLatitude()),
                            Double.parseDouble(MapDetailsList.list.get(i).getLongitude())));

                }
                LatLngBounds bounds = b.build();

                DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                int width = displayMetrics.widthPixels;
                int height = displayMetrics.heightPixels;

                // Change the padding as per needed
                CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width-200, height-200, 5);
                // map.setCenter(bounds.getCenter());

                map.animateCamera(cu);

            }

        } catch (Exception e) {

        }

http://i64.tinypic.com/2qjybh4.png

http://i63.tinypic.com/flzwus.png

http://i63.tinypic.com/112g5fm.png

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.