У меня 10 маркеров в GoogleMap
. Я хочу максимально увеличить масштаб и держать все маркеры в поле зрения? В более ранней версии этого можно было добиться с помощью zoomToSpan()
, но в версии 2 я понятия не имею, как это сделать. Кроме того, я знаю радиус круга, который должен быть виден.
Android map v2 zoom, чтобы показать все маркеры
Ответы (13)
Вы должны использовать класс 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
В одном комментарии отмечается, что использование этого метода только для одного маркера приводит к тому, что масштаб карты устанавливается на «причудливый» уровень масштабирования (который, я считаю, является максимальным уровнем масштабирования, доступным для данного местоположения). Я думаю, это ожидаемо, потому что:
- Экземпляр
LatLngBounds bounds
будет иметь свойствоnortheast
, равноеsouthwest
, что означает, что часть площади земли, покрытая этимbounds
, равна нулю. (Это логично, поскольку у одного маркера нет области.) - Передавая
bounds
вCameraUpdateFactory.newLatLngBounds
, вы, по сути, запрашиваете расчет такого уровня масштабирования, при которомbounds
(с нулевой областью) будет охватывать весь вид карты. - Вы действительно можете выполнить этот расчет на листе бумаги. Теоретический уровень масштабирования, который является ответом, равен + (положительная бесконечность). На практике объект
Map
не поддерживает это значение, поэтому он ограничивается более разумным максимальным уровнем, допустимым для данного местоположения.
Другими словами: как Map
объект может узнать, какой уровень масштабирования следует выбрать для отдельного местоположения? Возможно, оптимальное значение должно быть 20 (если оно представляет конкретный адрес). Или, может быть, 11 (если это город). Или, может быть, 6 (если представляет страну). API не так уж и умен, и решение остается за вами.
Итак, вы должны просто проверить, есть ли у markers
только одно местоположение, и если да, используйте одно из:
CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition())
- перейти к позиции маркера, оставить текущий масштаб без изменения.CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F)
- перейти к позиции маркера, установить произвольно выбранный уровень масштабирования 12.
addOnGlobalLayoutListener()
или post()
с соответствующим Runnable
. Именно по этой причине невозможно получить координаты экрана маркера в onCreate
- см. stackoverflow.com/q/14429877/1820695 Однако вы можете использовать некоторые методы даже до того, как произойдет макет - например. CameraUpdateFactory.newLatLngBounds()
с 4 параметрами.
- person andr; 01.08.2013
CameraPosition p1
. затем вы продолжаете вычисление CameraUpdate cu
, как указано выше, и выполняете map.moveCamera(cu)
. вы сохраняете текущее положение в p2
и проверяете, не выходит ли его масштаб за пределы желаемого диапазона - если да, вы создаете новый CameraPosition p3
на основе p2
, но с исправленным масштабированием и выдаете map.moveCamera(p1); map.animateCamera(CameraUpdateFactory.newCameraPosition(p3));
- предупреждение: никогда не тестировалось.
- person andr; 24.07.2014
final int width = getResources().getDisplayMetrics().widthPixels; final int height = getResources().getDisplayMetrics().heightPixels; final CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(latLngBounds, width, height, padding);
.
- person jfmg; 29.08.2015
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);
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
}
});
Я не мог использовать 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));
}
});
У меня работает нормально.
Из этого кода я показываю несколько маркеров с определенным увеличением на экране карты.
// Объявленные переменные
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);
Примечание. Это не решение исходного вопроса. Это решение одной из подзадач, описанных выше.
Решение для @andr Разъяснение 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.
это поможет .. из демонстраций API Google
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
У меня была аналогичная проблема, и следующий код решил проблему:
CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5)
в моем случае, как правило, разница в расположении не более двух соседних городов.
масштабирование, чтобы уместить все маркеры на карте Google Maps v2 а>
У меня есть еще один способ сделать то же самое, и он отлично работает. поэтому для того, чтобы показать все маркеры на экране, нам нужны центральная широта и масштаб. вот функция, которая предоставит вам оба и потребует в качестве входных данных все объекты 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.
Показать все маркеры на карте 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);
}
Используйте метод 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();
}
Я работал с той же проблемой для отображения нескольких маркеров в Котлине с использованием фрагмента
сначала объявите список маркеров
private lateinit var markers: MutableList<Marker>
инициализировать это в методе oncreate фрагмента
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//initialize markers list
markers = mutableListOf()
return inflater.inflate(R.layout.fragment_driver_map, container, false)
}
в OnMapReadyCallback добавить маркеры в список маркеров
private val callback = OnMapReadyCallback { googleMap ->
map = googleMap
markers.add(
map.addMarker(
MarkerOptions().position(riderLatLng)
.title("Driver")
.snippet("Driver")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))))
markers.add(
map.addMarker(
MarkerOptions().position(driverLatLng)
.title("Driver")
.snippet("Driver")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN))))
Все еще на обратном звонке
//create builder
val builder = LatLngBounds.builder()
//loop through the markers list
for (marker in markers) {
builder.include(marker.position)
}
//create a bound
val bounds = builder.build()
//set a 200 pixels padding from the edge of the screen
val cu = CameraUpdateFactory.newLatLngBounds(bounds,200)
//move and animate the camera
map.moveCamera(cu)
//animate camera by providing zoom and duration args, callBack set to null
map.animateCamera(CameraUpdateFactory.zoomTo(10f), 2000, null)
Веселые кодирующие ребята
//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