Збільшити карту 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
@Bar Ну, це частково так. Якщо бути точним: деякі методи руху не працюватимуть відразу після створення об’єкта карти. Причиною цього є те, що об’єкт карти ще не вимірювався, тобто він не пройшов процес компонування. Типовим виправленням є використання addOnGlobalLayoutListener()або post()з відповідним Runnable. Ось саме ця причина, через яку не можна виконати отримання координат екрана маркера onCreate- див. Stackoverflow.com/q/14429877/1820695 Однак ви можете використовувати деякі методи ще до того, як трапляється макет - наприклад. CameraUpdateFactory.newLatLngBounds()з 4 парами .
andr

1
Людина, ти врятуєш мій день ... насправді намагався зробити це самостійно, обчислювати межі вручну та збільшувати масштаби, поки маркер знаходиться в ньому ... працював досить некрасиво, але з твоїм простим методом це працює як шарм. Спасибі
Бібу

9
googleMap .setOnMapLoadedCallback (новий 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%.
noob

2
Прийнята відповідь іноді викликає дивне збільшення. Це працює як шарм. Це краща відповідь.
Hüseyin Bülbül

1
Ця відповідь працює краще, ніж прийнята, прийнята викликає певну втомлену поведінку.
Haytham

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, тому для мене він усе ще показав на карті за замовчуванням область / масштабування, перш ніж перемістити камеру на мої потреби
до

Як нанести накладки, коли мої два маркери торкаються меж карти.
Пратік Бутані

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 Пояснення 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.


гарне рішення, але якщо ви помістите об’єкт "cu" всередину onMapReady (), то в цьому випадку є неправильна поведінка: місцезнаходження отримане -> масштабування велике, тому зробіть це 16 -> тоді користувач знову збільшує -> місце, яке отримано, і камера повернути до рівня 16 . Це може бути проблемою, коли місце розташування буде отримано майже в режимі реального часу, оскільки воно продовжуватиме повертатися до рівня 16
Maher Nabil

"І 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

Для отримання координати центру та використання в CameraPosition використовуйте метод "getCenterCoordinate".

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, яким ви можете користуватися

Пара пари = 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.