Android地图v2缩放显示所有的标记

我在GoogleMap中有10个标记。我想要尽可能放大,并保持所有标记都在视野中?在早期版本中,这可以从zoomToSpan()实现,但在v2中,我不知道如何做到这一点。此外,我知道需要可见的圆的半径。

170433 次浏览

你应该使用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。

所以

我需要使用addOnGlobalLayoutListener来获得适当的示例

例如,你的谷歌地图在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."错误:< / p >
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
@Override
public void onMapLoaded() {
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
}
});

使用“getCenterCoordinate”方法获取中心坐标,并在camerposition中使用。

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();
}
   //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

请注意 -这不是原来问题的解决方案。这是讨论过的子问题之一的解决方案。

@andr 澄清2 -的解决方案

当边界中只有一个标记时,它真的很有问题,因为它的缩放级别设置为非常高的级别(水平21)。谷歌不提供任何设置最大缩放级别的方法。当有多个标记但它们彼此非常接近时,也会发生这种情况。同样的问题也会出现。

解决方案 -假设你想让你的地图永远不超过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演示

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

谷歌地图V2

以下解决方案适用于Android棉花糖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);

对我来说很好。

从这段代码中,我在地图屏幕上显示特定缩放的多个标记。

//声明变量

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

我有类似的问题,使用以下代码解决了这个问题:

CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5)一般来说,在我的情况下,位置差异不超过两个相邻城市。

缩放以适应地图谷歌上的所有标记

我有另一种方法来做同样的事情,效果很好。为了在屏幕上显示所有标记,我们需要一个中长和缩放级别。这里是一个函数,它会给你两个,需要所有标记的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 = getCenterWithZoomLevel(l1,l2,l3..); mGoogleMap.moveCamera (CameraUpdateFactory.newLatLngZoom(一对。首先,pair.second)); < / p >

你可以不用填充来让标记远离屏幕边界,你可以通过-1来调整缩放。

用谷歌地图显示所有标记

在这些方法中存储所有标记,并自动缩放显示谷歌地图中的所有标记。

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

我用一个片段在Kotlin中显示多个标记,解决了同样的问题

首先声明一个标记列表

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)

快乐的程序员们