Android map v2 zoom, чтобы показать все маркеры

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

Ответ 1

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

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

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

Затем получите объект описания движения с помощью factory: 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

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

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

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

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

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

Ответ 2

Google Map V2

Следующее решение работает для Android Marshmallow 6 (API 23, API 24, API 25). Это также работает в 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);

Ответ 3

So

Мне нужно было использовать 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
        }
    });

Ответ 4

Я не мог использовать 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 dimensions." ошибка:

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

Ответ 5

Работаю хорошо для меня.

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

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

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);

Ответ 6

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

Решение для @andr Разъяснение 2 -

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

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

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

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

float currentZoom = mMap.getCameraPosition().zoom;

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

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

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

Ответ 7

это поможет.. из google apis demos

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

Ответ 9

Используйте метод 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();
}

Ответ 10

У меня есть еще один способ сделать то же самое, что работает отлично. так что идея показать все маркеры на экране, нам нужен центр по длине и уровень масштабирования. вот функция, которая даст вам обоим и потребует в качестве входных данных все объекты-маркеры 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.

Ответ 11

Показать все маркеры на карте 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);
}

Ответ 12

   //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