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

时间:2013-02-12 08:17:28

标签: android google-maps google-maps-api-2 google-maps-android-api-2

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

13 个答案:

答案 0 :(得分:756)

您应该使用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构造等待这种情况发生。详细信息可以在对此答案的评论和剩余答案中找到。您还可以找到complete code for setting map extent using addOnGlobalLayoutListener here

澄清2

一条评论指出,仅将此方法用于一个标记会导致地图缩放设置为“奇异”缩放级别(我相信这是给定位置可用的最大缩放级别)。我认为这是因为:

  1. LatLngBounds bounds实例的northeast属性将等于southwest,这意味着此bounds所涵盖的地球部分正好为零。 (这是合乎逻辑的,因为单个标记没有区域。)
  2. 通过将bounds传递给CameraUpdateFactory.newLatLngBounds,您基本上会请求计算这样的缩放级别,bounds(零区域)将覆盖整个地图视图。
  3. 您实际上可以在一张纸上执行此计算。作为答案的理论缩放级别是+∞(正无穷大)。在实践中,Map对象不支持此值,因此它被限制为给定位置允许的更合理的最大级别。
  4. 另一种说法:Map对象如何知道它应该为单一位置选择什么缩放级别?也许最佳值应该是20(如果它代表一个特定的地址)。或者11(如果它代表一个小镇)。或者可能是6(如果它代表一个国家)。 API不是那么聪明,决定取决于你。

    因此,您应该只检查markers是否只有一个位置,如果是,请使用以下方法之一:

    • CameraUpdate cu = CameraUpdateFactory.newLatLng(marker.getPosition()) - 转到标记位置,保持当前缩放级别不变。
    • CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(marker.getPosition(), 12F) - 转到标记位置,将缩放级别设置为任意选择的值12。

答案 1 :(得分:99)

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

答案 2 :(得分: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
        }
    });

答案 3 :(得分: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));
 } 
});

答案 4 :(得分:8)

  

对我来说很好。

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

//声明变量

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

答案 5 :(得分:3)

注意 - 这不是原始问题的解决方案。这是所讨论的一个子问题的解决方案above

解决@andr 澄清2 -

当边界中只有一个标记并且因此缩放级别被设置为非常高的级别(级别21 )时,它确实存在问题。此时谷歌没有提供任何设置最大缩放级别的方法。当有超过1个标记但它们彼此非常接近时,也会发生这种情况。然后也会出现同样的问题。

解决方案 - 假设您希望地图永远不会超过16个缩放级别。然后做完 -

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

检查您的缩放级别是否已超过16级(或任何您想要的) -

float currentZoom = mMap.getCameraPosition().zoom;

如果此级别大于16,只有当标记非常少或所有标记彼此非常接近时才会这样,那么只需通过设置缩放级别就可以缩小特定位置的地图到16岁。

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

通过这种方式,你永远不会遇到&#34;奇怪的&#34; @andr也很好地解释了缩放级别。

答案 6 :(得分:2)

这将有助于..来自谷歌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));
                }
            });
        }
    }

查看此网址的明确信息。 https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java

答案 7 :(得分:1)

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

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

zoom to fit all markers on map google maps v2

答案 8 :(得分:0)

使用方法&#34; getCenterCoordinate&#34;获取中心坐标并在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();
}

答案 9 :(得分:0)

我还有另一种方法可以做同样的事情。因此,在屏幕上显示所有标记背后的想法我们需要一个中心lat长和缩放级别。这里的函数将为您提供并且需要所有标记的Latlng对象作为输入。

Glide.with(MainActivity.this)
                    .using(new FirebaseImageLoader())
                    .load(profilePicture)
                    .signature(new StringSignature(String.valueOf(System.currentTimeMillis())))
                    .into(profilePictures)
                    .listener(new RequestListener<URL, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, URL model, Target<GlideDrawable> target, boolean isFirstResource) {
                            progressDialogCreate.hide();
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(GlideDrawable resource, URL model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                            progressDialogCreate.hide();
                            return false;
                        }
                    });

此函数返回您可以使用的Pair对象

  

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

你可以代替使用填充来远离屏幕边界,你可以将缩放调整为-1。

答案 10 :(得分:0)

使用Google地图显示所有标记

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

jQuery(function ($) {

    if ($('marquee').length == 0) {
        return;
    }

    $('marquee').each(function () {

        let direction = $(this).attr('direction');
        let scrollamount = $(this).attr('scrollamount');
        let scrolldelay = $(this).attr('scrolldelay');

        let newMarquee = $('<div class="new-marquee"></div>');
        $(newMarquee).html($(this).html());
        $(newMarquee).attr('direction',direction);
        $(newMarquee).attr('scrollamount',scrollamount);
        $(newMarquee).attr('scrolldelay',scrolldelay);
        $(newMarquee).css('white-space', 'nowrap');

        let wrapper = $('<div style="overflow:hidden"></div>').append(newMarquee);
        $(this).replaceWith(wrapper);

    });

    function start_marquee() {

        let marqueeElements = document.getElementsByClassName('new-marquee');
        let marqueLen = marqueeElements.length
        for (let k = 0; k < marqueLen; k++) {


            let space = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
            let marqueeEl = marqueeElements[k];

            let direction = marqueeEl.getAttribute('direction');
            let scrolldelay = marqueeEl.getAttribute('scrolldelay') * 100;
            let scrollamount = marqueeEl.getAttribute('scrollamount');

            let marqueeText = marqueeEl.innerHTML;

            marqueeEl.innerHTML = marqueeText + space;
            marqueeEl.style.position = 'absolute'; 

            let width = (marqueeEl.clientWidth + 1);
            let i = (direction == 'rigth') ? width : 0;
            let step = (scrollamount !== undefined) ? parseInt(scrollamount) : 3;

            marqueeEl.style.position = '';
            marqueeEl.innerHTML = marqueeText + space + marqueeText + space;



            let x = setInterval( function () {

                if ( direction.toLowerCase() == 'left') {

                    i = i < width ? i + step : 1;
                    marqueeEl.style.marginLeft = -i + 'px';

                } else {

                    i = i > -width ? i - step : width;
                    marqueeEl.style.marginLeft = -i + 'px';

                }

            }, scrolldelay);

        }
    }

    start_marquee ();
});

答案 11 :(得分:0)

使用片段在Kotlin中显示多个标记时,我遇到了相同的问题

首先声明标记列表

private lateinit var markers: MutableList<Marker>

在frament的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)

快乐的编码专家

答案 12 :(得分:-3)

相关问题