แผนที่ 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 params
andr

1
ชายคุณช่วยชีวิตฉันด้วย ... จริง ๆ แล้วพยายามทำด้วยตัวเองคำนวณขอบเขตด้วยตนเองและซูมในขณะที่เครื่องหมายอยู่ในนั้น ... มันทำงานได้น่าเกลียด แต่ด้วยวิธีการง่าย ๆ ของคุณมันทำงานได้อย่างมีเสน่ห์ ขอบคุณ
Bibu

9
googleMap .setOnMapLoadedCallback (ใหม่ GoogleMap.OnMapLoadedCallback () {@Override โมฆะสาธารณะใน onMapLoaded () {googleMap.moveCamera (cu);}}); สิ่งนี้จะหลีกเลี่ยงข้อผิดพลาดในการวัด
Ramz

1
มันจะทำงานเป็นอย่างอื่น แต่เมื่อมีเครื่องหมายเดียวบนแผนที่มันจะซูมไปที่บางระดับที่แปลกประหลาดที่แผนที่จะเบลอ จะแก้ไขได้อย่างไร?
Utsav Gupta

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üseyinBülbül

1
คำตอบนี้ทำงานได้ดีกว่าคำตอบที่ยอมรับได้คำตอบที่ได้รับการยอมรับนั้นทำให้เกิดพฤติกรรมที่ผอมบาง
Haytham

13

ดังนั้น

ฉันต้องการใช้ addOnGlobalLayoutListener เพื่อรับตัวอย่างที่เหมาะสม

ตัวอย่างเช่น Google Map ของคุณอยู่ใน 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
มาที่นี่จากการกวดวิชา Udemy คนทำงานที่ยอดเยี่ยมพวกเขาใช้คำตอบของคุณในการแก้ปัญหา
Shantanu Shady

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 ดังนั้นสำหรับฉันมันยังคงแสดงแผนที่พื้นที่ / ซูมเริ่มต้นก่อนที่จะย้ายกล้องไปยังความต้องการของฉัน
จนถึง

วิธีการให้ช่องว่างภายในขณะที่เครื่องหมาย 2 ตัวของฉันสัมผัสกับขอบเขตแผนที่
Pratik Butani

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 ไม่มีวิธีการตั้งค่าระดับการซูมสูงสุด ณ จุดนี้ สิ่งนี้สามารถเกิดขึ้นได้เมื่อมีเครื่องหมายมากกว่า 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 เช่นกัน


วิธีแก้ปัญหาที่ดี แต่ถ้าคุณวางวัตถุ "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

ฉันมีปัญหาที่คล้ายกันโดยใช้รหัสต่อไปนี้แก้ไขปัญหา:

CameraUpdateFactory.newLatLngBounds(bounds, 200, 200, 5) โดยทั่วไปแล้วความแตกต่างของสถานที่ตั้งในกรณีของฉันคือไม่เกินสองเมืองเพื่อนบ้าน

ซูมเพื่อให้พอดีกับเครื่องหมายทั้งหมดบนแผนที่ google maps v2


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

ใช้วิธีการ "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();
}

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

ฟังก์ชั่นนี้คืนค่าวัตถุคู่ที่คุณสามารถใช้เช่น

คู่คู่ = 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.