Memposisikan MKMapView untuk menampilkan beberapa anotasi sekaligus

93

Saya punya beberapa anotasi yang ingin saya tambahkan ke MKMapView saya (bisa 0-n item, di mana n umumnya sekitar 5). Saya dapat menambahkan anotasi dengan baik, tetapi saya ingin mengubah ukuran peta agar sesuai dengan semua anotasi di layar sekaligus, dan saya tidak yakin bagaimana melakukan ini.

Saya telah melihat -regionThatFits:tetapi saya tidak yakin apa yang harus saya lakukan dengannya. Saya akan memposting beberapa kode untuk menunjukkan apa yang saya dapatkan sejauh ini. Saya pikir ini seharusnya menjadi tugas yang umumnya mudah tetapi sejauh ini saya merasa agak kewalahan dengan MapKit.

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{

location = newLocation.coordinate;
//One location is obtained.. just zoom to that location

MKCoordinateRegion region;
region.center = location;

//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta = 0.015;
span.longitudeDelta = 0.015;
region.span = span;
// Set the region here... but I want this to be a dynamic size
// Obviously this should be set after I've added my annotations
[mapView setRegion:region animated:YES];

// Test data, using these as annotations for now
NSArray *arr = [NSArray arrayWithObjects:@"one", @"two", @"three", @"four", nil];
float ex = 0.01;
for (NSString *s in arr) {
    JBAnnotation *placemark = [[JBAnnotation alloc] initWithLat:(location.latitude + ex) lon:location.longitude];
    [mapView addAnnotation:placemark];
    ex = ex + 0.005;
}
    // What do I do here?
    [mapView setRegion:[mapView regionThatFits:region] animated:YES];
}

Perhatikan, ini semua terjadi saat saya menerima pembaruan lokasi ... Saya tidak tahu apakah itu tempat yang tepat untuk melakukan ini. Jika tidak, di manakah tempat yang lebih baik? -viewDidLoad?

Terima kasih sebelumnya.

jbrennan.dll
sumber

Jawaban:

137

The Link diposting oleh Jim sekarang mati, tetapi saya dapat menemukan kode (yang saya punya tempat-bookmark). Semoga ini membantu.

- (void)zoomToFitMapAnnotations:(MKMapView *)mapView { 
    if ([mapView.annotations count] == 0) return; 

    CLLocationCoordinate2D topLeftCoord; 
    topLeftCoord.latitude = -90; 
    topLeftCoord.longitude = 180; 

    CLLocationCoordinate2D bottomRightCoord; 
    bottomRightCoord.latitude = 90; 
    bottomRightCoord.longitude = -180; 

    for(id<MKAnnotation> annotation in mapView.annotations) { 
        topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude); 
        topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude); 
        bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude); 
        bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude); 
    } 

    MKCoordinateRegion region; 
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5; 
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;      

    // Add a little extra space on the sides
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; 

    region = [mapView regionThatFits:region]; 
    [mapView setRegion:region animated:YES]; 
}
Mustafa
sumber
14
Aku bisa menciummu. Ini hanya menghemat banyak waktu saya. Saya menambahkan kode di atas untuk menangani 1 lokasi. Itu menjadi sedikit dekat dan pribadi. Saya akan memposting itu sebagai tanggapan karena komentar cenderung mengunyah kode.
Michael Reed
Terima kasih banyak. Saya menambahkan ini ke subkelas MKMapViewdan mengubah metode menjadi - (void) zoomToFitAnnotations:(BOOL)animated. Bekerja dengan sempurna!
simonbs
1
itu bekerja dengan sangat baik. itu juga berguna. Anda dapat mengubah memperkecil atau memperbesar nilai. jadi region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; /// ubah nilai. ketika Anda meningkatkan nilai: perkecil ........ saat Anda mengurangi nilai: perbesar misalnya: region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 4.1;
Erhan Demirci
1
@ MR.Mustafa: Ini bekerja, luar biasa! Tapi menurutku menyelesaikan masalah ini sudah cukup. Jadi tolong ada yang menjelaskan cara kerjanya. Atau melalui tautan apa pun. Maaf jika saya konyol, saya seorang pemula. Tolong dukung. Terima kasih
Siddarth Hailstorm
1
@ Mustafa ... Terima kasih sudah menyelamatkan hariku.
Vvk
133

Mengapa begitu rumit?

MKCoordinateRegion coordinateRegionForCoordinates(CLLocationCoordinate2D *coords, NSUInteger coordCount) {
    MKMapRect r = MKMapRectNull;
    for (NSUInteger i=0; i < coordCount; ++i) {
        MKMapPoint p = MKMapPointForCoordinate(coords[i]);
        r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
    }
    return MKCoordinateRegionForMapRect(r);
}
saya 2
sumber
6
luar biasa betapa lebih sederhana, lebih bersih, dan lebih mudah ini daripada alternatif yang diposting. sebenarnya, Anda dapat menyederhanakan ini lebih jauh karena tidak perlu mengonversi ke MKCoordinateRegion - cukup panggil setVisibleMapRect: di MKMapView Anda dengan MKMapRect yang Anda buat di sini.
lensovet
2
Anotasi terkadang menempel di bagian atas peta dan tidak terlihat. Adakah masukan tentang pendekatan terbaik untuk meningkatkan zoom setelah MKCoordinateRegion dibuat?
Kyle C
3
@KC[mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(20.0f, 20.0f, 20.0f, 20.0f) animated:animated];
pengguna
Bagaimana Anda membuat CLLocationCoordinate2D *coordsarray? Menggunakan malloc()?
Hlung
3
@Tokopedia Saya menambahkan ini ke sebelum kembali ryang pada dasarnya memperkecil 20 persenCGFloat zoomOutPercent = 0.2f; r = MKMapRectMake(r.origin.x-r.size.width*zoomOutPercent, r.origin.y-r.size.height*zoomOutPercent, r.size.width*(1+zoomOutPercent*2), r.size.height*(1+zoomOutPercent*2));
Loozie
44

Saya telah melakukan sesuatu yang mirip dengan ini untuk memperkecil (atau masuk) ke area yang menyertakan anotasi titik dan lokasi saat ini. Anda dapat mengembangkannya dengan mengulang-ulang anotasi Anda.

Langkah dasarnya adalah:

  • Hitung garis lintang / bujur min
  • Hitung lintang / bujur maks
  • Buat objek CLLocation untuk dua titik ini
  • Hitung jarak antar titik
  • Buat wilayah menggunakan titik pusat antara titik dan jarak yang diubah menjadi derajat
  • Lewati wilayah ke MapView untuk menyesuaikan
  • Gunakan wilayah yang disesuaikan untuk mengatur wilayah MapView
    -(IBAction)zoomOut:(id)sender {

        CLLocationCoordinate2D southWest = _newLocation.coordinate;
        CLLocationCoordinate2D northEast = southWest;

        southWest.latitude = MIN(southWest.latitude, _annotation.coordinate.latitude);
        southWest.longitude = MIN(southWest.longitude, _annotation.coordinate.longitude);

        northEast.latitude = MAX(northEast.latitude, _annotation.coordinate.latitude);
        northEast.longitude = MAX(northEast.longitude, _annotation.coordinate.longitude);

        CLLocation *locSouthWest = [[CLLocation alloc] initWithLatitude:southWest.latitude longitude:southWest.longitude];
        CLLocation *locNorthEast = [[CLLocation alloc] initWithLatitude:northEast.latitude longitude:northEast.longitude];

        // This is a diag distance (if you wanted tighter you could do NE-NW or NE-SE)
        CLLocationDistance meters = [locSouthWest getDistanceFrom:locNorthEast];

        MKCoordinateRegion region;
        region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0;
        region.center.longitude = (southWest.longitude + northEast.longitude) / 2.0;
        region.span.latitudeDelta = meters / 111319.5;
        region.span.longitudeDelta = 0.0;

        _savedRegion = [_mapView regionThatFits:region];
        [_mapView setRegion:_savedRegion animated:YES];

        [locSouthWest release];
        [locNorthEast release];
    }
Donald Byrd
sumber
Sepertinya ini cara yang harus dilakukan. Terima kasih!
jbrennan
1
Berhasil membuat ini berfungsi menggunakan MKCoordinateRegionMake: gist.github.com/1599700 jika ada yang masih ingin melakukannya dengan cara ini.
chakrit
region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0; Terima kasih untuk itu
Tony
Apakah ini berfungsi dengan titik-titik di kedua sisi meridian? Ekuator?
Eliot
1
Kode ini menempatkan lokasi di luar layar ketika lokasi memiliki nilai y yang serupa. Contoh, menampilkan dua lokasi di (50, -4) & (100, -3) akan memperbesar peta terlalu jauh, menempatkan koordinat di sisi kiri dan kanan layar.
pengguna
21

Saya punya jawaban yang berbeda. Saya akan menerapkan algoritma zoom-to-fit sendiri, tetapi saya pikir Apple harus memiliki cara untuk melakukan apa yang kami inginkan tanpa banyak pekerjaan. Menggunakan dokumen API dengan cepat menunjukkan bahwa saya dapat menggunakan MKPolygon untuk melakukan apa yang diperlukan:

/* this simply adds a single pin and zooms in on it nicely */
- (void) zoomToAnnotation:(MapAnnotation*)annotation {
    MKCoordinateSpan span = {0.027, 0.027};
    MKCoordinateRegion region = {[annotation coordinate], span};
    [mapView setRegion:region animated:YES];
}

/* This returns a rectangle bounding all of the pins within the supplied
   array */
- (MKMapRect) getMapRectUsingAnnotations:(NSArray*)theAnnotations {
    MKMapPoint points[[theAnnotations count]];

    for (int i = 0; i < [theAnnotations count]; i++) {
        MapAnnotation *annotation = [theAnnotations objectAtIndex:i];
        points[i] = MKMapPointForCoordinate(annotation.coordinate);
    }

    MKPolygon *poly = [MKPolygon polygonWithPoints:points count:[theAnnotations count]];

    return [poly boundingMapRect];
}

/* this adds the provided annotation to the mapview object, zooming 
   as appropriate */
- (void) addMapAnnotationToMapView:(MapAnnotation*)annotation {
    if ([annotations count] == 1) {
        // If there is only one annotation then zoom into it.
        [self zoomToAnnotation:annotation];
    } else {
        // If there are several, then the default behaviour is to show all of them
        //
        MKCoordinateRegion region = MKCoordinateRegionForMapRect([self getMapRectUsingAnnotations:annotations]);

        if (region.span.latitudeDelta < 0.027) {
            region.span.latitudeDelta = 0.027;
        }

        if (region.span.longitudeDelta < 0.027) {
            region.span.longitudeDelta = 0.027;
        }
        [mapView setRegion:region];
    }

    [mapView addAnnotation:annotation];
    [mapView selectAnnotation:annotation animated:YES];
}

Semoga ini membantu.

PKCLsoft
sumber
Tidak ada masalah. Biasanya ada cara yang lebih baik jika Anda mau dan punya waktu untuk menggunakannya.
PKCLsoft
Saya menemukan ini menempatkan pin agak terlalu dekat dengan tepi layar. Coba tambahkan annotationsRegion.span.latitudeDelta = annotationsRegion.span.latitudeDelta * kEventMapDetailBorderFactor; tepat sebelum setRegion.
Adam Eberbach
Anda benar @AdamEberbach, tetapi tampaknya klip Anda menyertakan konstanta yang tidak tersedia. Apakah Anda menemukan nilai yang memberikan garis tepi "bagus" di sekeliling pin?
PKCLsoft
Jawaban Code Commander di bawah ini tentang penggunaan metode showAnnotations baru dengan iOS7 menambahkan margin yang bagus, yang sebenarnya bekerja lebih baik, meskipun kode ini lebih keren.
James Toomey
14

kamu juga bisa melakukannya dengan cara ini ..

// Position the map so that all overlays and annotations are visible on screen.
MKMapRect regionToDisplay = [self mapRectForAnnotations:annotationsToDisplay];
if (!MKMapRectIsNull(regionToDisplay)) myMapView.visibleMapRect = regionToDisplay;

- (MKMapRect) mapRectForAnnotations:(NSArray*)annotationsArray
{
    MKMapRect mapRect = MKMapRectNull;

    //annotations is an array with all the annotations I want to display on the map
    for (id<MKAnnotation> annotation in annotations) { 

        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);

        if (MKMapRectIsNull(mapRect)) 
        {
            mapRect = pointRect;
        } else 
        {
            mapRect = MKMapRectUnion(mapRect, pointRect);
        }
    }

     return mapRect;
}
Manish Ahuja
sumber
13

Berdasarkan informasi dan saran dari semua orang yang saya temukan berikut ini. Terima kasih untuk semua orang dalam diskusi ini untuk kontribusinya :) Ini akan masuk ke dalam tampilan Controller yang berisi mapView.

- (void)zoomToFitMapAnnotations { 

if ([self.mapView.annotations count] == 0) return; 

int i = 0;
MKMapPoint points[[self.mapView.annotations count]];

//build array of annotation points
for (id<MKAnnotation> annotation in [self.mapView annotations])
        points[i++] = MKMapPointForCoordinate(annotation.coordinate);

MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];

[self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES]; 
}
nh32rg
sumber
Ini harus mendapatkan lebih banyak suara. Sangat tepat dan langsung ke sasaran.
Natasha
5

Dalam kasus saya, saya mulai dengan objek CLLocation dan membuat anotasi untuk masing-masing objek.
Saya hanya perlu menempatkan dua anotasi, jadi saya memiliki pendekatan sederhana untuk membangun array poin, tetapi itu dapat dengan mudah diperluas untuk membangun array dengan panjang yang sewenang-wenang yang diberikan satu set CLLocations.

Inilah implementasi saya (tidak perlu membuat MKMapPoints):

//start with a couple of locations
CLLocation *storeLocation = store.address.location.clLocation;
CLLocation *userLocation = [LBLocationController sharedController].currentLocation;

//build an array of points however you want
CLLocationCoordinate2D points[2] = {storeLocation.coordinate, userLocation.coordinate};

//the magic part
MKPolygon *poly = [MKPolygon polygonWithCoordinates:points count:2];
[self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect])];
jacobsimeon.dll
sumber
5

Menggunakan Swift, poligon, dan beberapa padding tambahan, saya menggunakan yang berikut ini:

func zoomToFit() {
    var allLocations:[CLLocationCoordinate2D] = [
        CLLocationCoordinate2D(latitude: 32.768805, longitude: -117.167119),
        CLLocationCoordinate2D(latitude: 32.770480, longitude: -117.148385),
        CLLocationCoordinate2D(latitude: 32.869675, longitude: -117.212929)
    ]

    var poly:MKPolygon = MKPolygon(coordinates: &allLocations, count: allLocations.count)

    self.mapView.setVisibleMapRect(poly.boundingMapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: false)
}

Lindsay Thurmond
sumber
setVisibleMapRect (...). Saya melakukan matematika sendiri ... dengan buruk.
CodeReaper
3

Ada metode baru di 'MKMapView' mulai iOS 7 yang dapat Anda gunakan

Pernyataan

CEPAT

func showAnnotations(_ annotations: [AnyObject]!,
            animated animated: Bool)

TUJUAN-C

- (void)showAnnotations:(NSArray *)annotations
               animated:(BOOL)animated

Parameter

annotations Anotasi yang Anda inginkan untuk terlihat di peta. animasi YA jika Anda ingin perubahan wilayah peta menjadi animasi, atau TIDAK jika Anda ingin peta segera menampilkan wilayah baru tanpa animasi.

Diskusi

Memanggil metode ini memperbarui nilai di properti wilayah dan kemungkinan properti lain untuk mencerminkan wilayah peta baru.

Matt
sumber
3

Saya tahu ini adalah pertanyaan lama tetapi, jika Anda ingin menampilkan semua anotasi SUDAH DI peta gunakan ini:

 mapView.showAnnotations(mapView.annotations, animated: true)
Paul Lehn
sumber
3

Berikut adalah Setara SWIFT (Dikonfirmasi Bekerja di: Xcode6.1, SDK 8.2) untuk Jawaban Mustafa:

func zoomToFitMapAnnotations() {
    if self.annotations.count == 0 {return}

    var topLeftCoordinate = CLLocationCoordinate2D(latitude: -90, longitude: 180)
    var bottomRightCoordinate = CLLocationCoordinate2D(latitude: 90, longitude: -180)

    for object in self.annotations {
        if let annotation = object as? MKAnnotation {
            topLeftCoordinate.longitude = fmin(topLeftCoordinate.longitude, annotation.coordinate.longitude)
            topLeftCoordinate.latitude = fmax(topLeftCoordinate.latitude, annotation.coordinate.latitude)
            bottomRightCoordinate.longitude = fmax(bottomRightCoordinate.longitude, annotation.coordinate.longitude)
            bottomRightCoordinate.latitude = fmin(bottomRightCoordinate.latitude, annotation.coordinate.latitude)
        }
    }

    let center = CLLocationCoordinate2D(latitude: topLeftCoordinate.latitude - (topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 0.5, longitude: topLeftCoordinate.longitude - (topLeftCoordinate.longitude - bottomRightCoordinate.longitude) * 0.5)

    print("\ncenter:\(center.latitude) \(center.longitude)")
    // Add a little extra space on the sides
    let span = MKCoordinateSpanMake(fabs(topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 1.01, fabs(bottomRightCoordinate.longitude - topLeftCoordinate.longitude) * 1.01)
    print("\nspan:\(span.latitudeDelta) \(span.longitudeDelta)")

    var region = MKCoordinateRegion(center: center, span: span)


    region = self.regionThatFits(region)

    self.setRegion(region, animated: true)

}
Saru
sumber
1
Hai iOS_Developer. Terima kasih atas konversi Swift. Bagi saya ini tidak berfungsi karena saya pikir Anda kehilangan dua "fmax" daripada "fmin" untuk topLeftCoordinate.latitude dan bottomRightCoordinate.longitude.
Philipp Otto
2

Salah satu solusi yang mungkin adalah mengukur jarak antara lokasi saat ini dan semua anotasi dan menggunakan metode MKCoordinateRegionMakeWithDistance untuk membuat wilayah yang memiliki jarak sedikit lebih jauh daripada anotasi terjauh.

Hal ini tentu saja akan menjadi lebih lambat jika semakin banyak anotasi yang Anda tambahkan.

criscokid
sumber
Saya akan melalui bagian komentar hanya untuk memvalidasi diri saya sendiri. Senang karena orang lain berpikir seperti saya :-) Karena saya hanya menambahkan dua anotasi (titik awal dan akhir), saya tidak merasa lambat.
thandasoru
2
- (void)zoomToFitMapAnnotations {

if ([self.mapview.annotations count] == 0) return;

int i = 0;
MKMapPoint points[[self.mapview.annotations count]];

//build array of annotation points
for (id<MKAnnotation> annotation in [self.mapview annotations])
    points[i++] = MKMapPointForCoordinate(annotation.coordinate);

MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];

[self.mapview setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES];
}
pengguna3042729
sumber
2

Berdasarkan jawaban luar biasa oleh me2(sekarang di Swift)

func coordinateRegionForCoordinates(coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
    var rect: MKMapRect = MKMapRectNull
    for coord in coords {
        let point: MKMapPoint = MKMapPointForCoordinate(coord)
        rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0))
    }
    return MKCoordinateRegionForMapRect(rect)
}
tilo
sumber
1

Menambahkan sedikit klausa if untuk menangani 1 lokasi- untuk ditambahkan ke cuplikan kode cound mustufa. Fungsi zoomToAnnotation pkclSoft digunakan untuk itu:

if ([mapView.annotations count] == 1){
    MKCoordinateSpan span = {0.027, 0.027};
    region.span = span;
    CLLocationCoordinate2D singleCoordinate = [[mapView.annotations objectAtIndex:0] coordinate];
    region.center.latitude = singleCoordinate.latitude;
    region.center.longitude = singleCoordinate.longitude;
}
else
{
    // mustufa's code
}
Michael Reed
sumber
1

kode ini berfungsi untuk saya, ini menunjukkan semua pin dengan lokasi saat ini, semoga ini membantu Anda,

func setCenterForMap() {
    var mapRect: MKMapRect = MKMapRectNull
    for loc in mapView.annotations {
        let point: MKMapPoint = MKMapPointForCoordinate(loc.coordinate)
        print( "location is : \(loc.coordinate)");
        mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0))
    }
    if (locationManager.location != nil) {
        let point: MKMapPoint = MKMapPointForCoordinate(locationManager.location!.coordinate)
        print( "Cur location is : \(locationManager.location!.coordinate)");
        mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0))
    }

    mapView.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: true)

}
Patel Jigar
sumber
0

Saya harap ini setidaknya relevan, inilah yang saya kumpulkan untuk Mono (berdasarkan jawaban pkclSoft):

void ZoomMap (MKMapView map)
{
    var annotations = map.Annotations;

    if (annotations == null || annotations.Length == 0) 
        return;

    var points = annotations.OfType<MapAnnotation> ()
                            .Select (s => MKMapPoint.FromCoordinate (s.Coordinate))
                            .ToArray ();            

    map.SetVisibleMapRect(MKPolygon.FromPoints (points).BoundingMapRect, true); 
}
nullable
sumber
0
CLLocationCoordinate2D min = CLLocationCoordinate2DMake(99999.0, 99999.0);
CLLocationCoordinate2D max = CLLocationCoordinate2DMake(-99999.0, -99999.0);

// find max/min....

// zoom to cover area
// TODO: Maybe better using a MKPolygon which can calculate its own fitting region.
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((max.latitude + min.latitude) / 2.0, (max.longitude + min.longitude) / 2.0);
MKCoordinateSpan span = MKCoordinateSpanMake(max.latitude - min.latitude, max.longitude - min.longitude);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);

[_mapView setRegion:[_mapView regionThatFits:region] animated:YES];
VSN
sumber
0

Berdasarkan respons me2, saya menulis kategori untuk MKMapView untuk menambahkan beberapa margin dan melewati anotasi lokasi pengguna:

@interface MKMapView (ZoomToFitAnnotations)
- (void)zoomToFitAnnotations:(BOOL)animated;
@end

@implementation MKMapView (ZoomToFitAnnotations)
- (void)zoomToFitAnnotations:(BOOL)animated {
    if (self.annotations.count == 0)
        return;

    MKMapRect rect = MKMapRectNull;
    for (id<MKAnnotation> annotation in self.annotations) {
        if ([annotation isKindOfClass:[MKUserLocation class]] == false) {
            MKMapPoint point = MKMapPointForCoordinate(annotation.coordinate);
            rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0));
        }
    }

    MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect);
    region.span.longitudeDelta *= 2; // Margin
    region.span.latitudeDelta *= 2; // Margin
    [self setRegion:region animated:animated];
}
@end
Tomasz
sumber
0

Karena saya tidak dapat mengomentari sebuah jawaban, saya ingin menambahkan sedikit kenyamanan saya ke dalam jawaban @ me2 (karena saya pikir itu adalah pendekatan yang paling elegan Ditemukan di sini).

Untuk proyek pribadi saya, saya hanya menambahkan kategori pada kelas MKMapView untuk merangkum fungsionalitas "area terlihat" untuk operasi umum: pengaturan untuk dapat melihat semua anotasi yang dimuat saat ini pada contoh MKMapView. hasilnya adalah ini:

file .h

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated;
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated;


@end

file .m

#import "MKMapView+Extensions.h"

@implementation MKMapView (Extensions)

/**
 *  Changes the currently visible portion of the map to a region that best fits all the currently loadded annotations on the map, and it optionally animates the change.
 *
 *  @param animated is the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated
{
    MKMapView * mapView = self;

    NSArray * annotations = mapView.annotations;

    [self ij_setVisibleRectToFitAnnotations:annotations animated:animated];

}


/**
 *  Changes the currently visible portion of the map to a region that best fits the provided annotations array, and it optionally animates the change.
    All elements from the array must conform to the <MKAnnotation> protocol in order to fetch the coordinates to compute the visible region of the map.
 *
 *  @param annotations an array of elements conforming to the <MKAnnotation> protocol, holding the locations for which the visible portion of the map will be set.
 *  @param animated    wether or not the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated
{
    MKMapView * mapView = self;

    MKMapRect r = MKMapRectNull;
    for (id<MKAnnotation> a in annotations) {
        ZAssert([a conformsToProtocol:@protocol(MKAnnotation)], @"ERROR: All elements of the array MUST conform to the MKAnnotation protocol. Element (%@) did not fulfill this requirement", a);
        MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
        //MKMapRectUnion performs the union between 2 rects, returning a bigger rect containing both (or just one if the other is null). here we do it for rects without a size (points)
        r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
    }

    [mapView setVisibleMapRect:r animated:animated];

}

@end

Seperti yang Anda lihat, sejauh ini saya telah menambahkan 2 metode: satu untuk menyetel wilayah yang terlihat dari peta ke salah satu yang cocok dengan semua anotasi yang saat ini dimuat pada instance MKMapView, dan metode lain untuk menyetelnya ke berbagai objek. Jadi untuk mengatur wilayah mapView yang terlihat, kodenya akan sesederhana:

   //the mapView instance  
    [self.mapView ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:animated]; 

Saya harap ini membantu =)

Robertibiris
sumber
0

Pertimbangkan ekstensi ini:

extension MKCoordinateRegion {
    init(locations: [CLLocationCoordinate2D], marginMultiplier: Double = 1.1) {
        let mapRect = locations.reduce(MKMapRect(), {
            let point = MKMapPointForCoordinate($1)
            let rect = MKMapRect(origin: point, size: MKMapSize(width: 0.0, height: 0.0))
            return MKMapRectUnion($0, rect)
        })

        var coordinateRegion = MKCoordinateRegionForMapRect(mapRect)
        coordinateRegion.span.latitudeDelta *= marginMultiplier
        coordinateRegion.span.longitudeDelta *= marginMultiplier
        self = coordinateRegion
    }
}
nsmeme.dll
sumber
0

Versi 5 cepat:

   func regionFor(coordinates coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
        var r = MKMapRect.null

        for i in 0 ..< coords.count {
            let p = MKMapPoint(coords[i])

            r = r.union(MKMapRect(x: p.x, y: p.y, width: 0, height: 0))
        }

        return MKCoordinateRegion(r)
    }
Stéphane de Luca
sumber
0

Menambahkan tambahan pada jawaban Stéphane de Luca . Di sini kita dapat menyimpan UserLocation plus Anotasi Kustom agar sesuai dengan MKMapView

 private func centerViewOnUserLocation() {
    
    if selectedLatitudeFromPreviousVC?.description != nil && selectedLongitudeFromPreviousVC?.description != nil {
        
        if let location = locationManager.location?.coordinate {
            let region = regionFor(coordinates: [
                CLLocationCoordinate2D(latitude: selectedLatitudeFromPreviousVC!, longitude: selectedLongitudeFromPreviousVC!),
                location])
            mkmapView.setRegion(region, animated: true)
        }
    } else {
        if let location = locationManager.location?.coordinate {
            let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
            mkmapView.setRegion(region, animated: true)
        }
    }
}

private func regionFor(coordinates coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
    var r = MKMapRect.null

    for i in 0 ..< coords.count {
        let p = MKMapPoint(coords[i])
        r = r.union(MKMapRect(x: p.x, y: p.y, width: 0, height: 0))
    }

    var coordinateRegion = MKCoordinateRegion(r)
    coordinateRegion.span.latitudeDelta *= 1.5
    coordinateRegion.span.longitudeDelta *= 1.5
    return coordinateRegion
}

masukkan deskripsi gambar di sini

Sreekanth G
sumber