Posizionamento di MKMapView per mostrare più annotazioni contemporaneamente


92

Ho diverse annotazioni che voglio aggiungere al mio MKMapView (potrebbe 0-n elementi, dove n è generalmente intorno a 5). Posso aggiungere le annotazioni bene, ma voglio ridimensionare la mappa per adattarla contemporaneamente a tutte le annotazioni sullo schermo e non sono sicuro di come farlo.

Ho guardato -regionThatFits:ma non sono abbastanza sicuro di cosa farne. Inserirò del codice per mostrare quello che ho ottenuto finora. Penso che questo dovrebbe essere un compito generalmente semplice, ma finora mi sento un po 'sopraffatto da 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];
}

Nota, tutto questo accade quando ricevo un aggiornamento sulla posizione ... Non so se sia un posto appropriato per farlo. In caso contrario, dove sarebbe un posto migliore? -viewDidLoad?

Grazie in anticipo.

Risposte:



137

Il collegamento pubblicato da Jim ora è morto, ma sono riuscito a trovare il codice (che avevo aggiunto ai segnalibri da qualche parte). Spero che questo ti aiuti.

- (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]; 
}

14
Potrei baciarti. Questo mi ha solo fatto risparmiare un sacco di tempo. Ho aggiunto il codice a quanto sopra per gestire 1 posizione. È diventato un po 'intimo e personale. Lo posterò come risposta poiché i commenti tendono a masticare il codice.
Michael Reed

Grazie mille. L'ho aggiunto a una sottoclasse di MKMapViewe ho cambiato il metodo in - (void) zoomToFitAnnotations:(BOOL)animated. Funziona perfettamente!
simonbs

1
funziona molto bene. inoltre è utile. è possibile modificare lo zoom indietro o lo zoom avanti. quindi region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; /// cambia valore. quando aumenti il ​​valore: rimpicciolisci ........ quando diminuisci il valore: ingrandisci ad esempio: region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 4.1;
Erhan Demirci

1
@ MR.Mustafa: Funziona, fantastico! Ma non credo che risolvere il problema sia sufficiente. Quindi per favore qualcuno mi spieghi come funziona. O tramite qualsiasi link. Scusa se sono stupido, sono un principiante. Supporto di Pls. Grazie
Siddarth Hailstorm

1
@Mustafa ... Grazie mi ha salvato la giornata.
Vvk

133

Perché così complicato?

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

6
incredibile quanto sia più semplice, pulito e facile rispetto alle alternative pubblicate. in effetti, puoi semplificarlo ulteriormente perché non è necessario convertire in MKCoordinateRegion - basta chiamare setVisibleMapRect: sul tuo MKMapView con MKMapRect che crei qui.
lensovet

2
Le annotazioni a volte sono attaccate alla parte superiore della mappa e non sono visibili. Qualche input sull'approccio migliore per aumentare lo zoom dopo aver creato MKCoordinateRegion?
Kyle C

3
@KyleC[mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(20.0f, 20.0f, 20.0f, 20.0f) animated:animated];
utente

Come si crea l' CLLocationCoordinate2D *coordsarray? Usando malloc()?
Hlung

3
@KyleC. Ho aggiunto questo a prima di tornare, rche sostanzialmente CGFloat 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));
riduce il

44

Ho fatto qualcosa di simile a questo per ridurre (o ingrandire) un'area che includeva un'annotazione di un punto e la posizione corrente. Puoi espanderlo scorrendo le tue annotazioni.

I passaggi fondamentali sono:

  • Calcola latitudine / longitudine min
  • Calcola la latitudine / longitudine massima
  • Creare oggetti CLLocation per questi due punti
  • Calcola la distanza tra i punti
  • Crea una regione utilizzando il punto centrale tra i punti e la distanza convertita in gradi
  • Passa la regione in MapView per adattarla
  • Usa la regione modificata per impostare la regione di 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];
    }

Questa sembra la strada da percorrere. Grazie!
jbrennan

1
Sono riuscito a farlo funzionare utilizzando MKCoordinateRegionMake: gist.github.com/1599700 nel caso qualcuno volesse ancora farlo in questo modo.
chakrit

region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0; Grazie per questo
Tony

Funziona con i punti su entrambi i lati del meridiano? L'equatore?
Eliot

1
Questo codice posiziona le posizioni fuori dallo schermo quando le posizioni hanno un valore y simile. Esempio, mostrando due posizioni a (50, -4) e (100, -3) ingrandirà la mappa troppo lontano, posizionando le coordinate fuori dal lato sinistro e destro dello schermo.
utente

21

Ho una risposta diversa. Stavo per implementare l'algoritmo zoom-to-fit da solo, ma ho pensato che Apple doveva avere un modo per fare quello che volevamo senza così tanto lavoro. L'utilizzo dell'API doco ha mostrato rapidamente che potevo usare MKPolygon per fare ciò che era necessario:

/* 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];
}

Spero che questo ti aiuti.


Nessun problema. Di solito c'è un modo migliore se sei disposto e hai il tempo da dedicare ad esso.
PKCLsoft

Ho scoperto che questo mette i perni un po 'troppo vicino al bordo dello schermo. Prova ad aggiungere annotationsRegion.span.latitudeDelta = annotationsRegion.span.latitudeDelta * kEventMapDetailBorderFactor; appena prima di setRegion.
Adam Eberbach

Hai ragione @AdamEberbach, ma sembra che la tua clip includa una costante che non è disponibile. Hai trovato un valore che fornisse un bordo "carino" attorno ai perni?
PKCLsoft

La risposta di Code Commander di seguito sull'utilizzo del nuovo metodo showAnnotations con iOS7 aggiunge un bel margine, che in realtà funziona meglio, sebbene questo codice sia più interessante.
James Toomey

14

puoi farlo anche in questo modo ..

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

13

Sulla base delle informazioni e dei suggerimenti di tutti, mi è venuto in mente quanto segue. Grazie a tutti in questa discussione per aver contribuito :) Questo andrebbe nella vista Controller che contiene il 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]; 
}

Questo dovrebbe ottenere più voti positivi. Molto preciso e al punto.
Natasha

5

Nel mio caso, inizio con gli oggetti CLLocation e creo annotazioni per ciascuno di essi.
Ho solo bisogno di inserire due annotazioni, quindi ho un approccio semplice per costruire l'array di punti, ma potrebbe essere facilmente espanso per costruire un array con una lunghezza arbitraria dato un insieme di CLLocations.

Ecco la mia implementazione (non richiede la creazione di 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])];

5

Usando Swift, un poligono e un po 'di imbottitura extra ho usato quanto segue:

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


setVisibleMapRect (...). Facevo i conti da solo ... male.
CodeReaper

3

C'è un nuovo metodo in "MKMapView" a partire da iOS 7 che puoi utilizzare

Dichiarazione

SWIFT

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

OBIETTIVO-C

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

Parametri

annotazioni Le annotazioni che si desidera siano visibili nella mappa. animato SÌ se si desidera che la modifica della regione della mappa sia animata o NO se si desidera che la mappa visualizzi immediatamente la nuova regione senza animazioni.

Discussione

La chiamata a questo metodo aggiorna il valore nella proprietà della regione e potenzialmente altre proprietà per riflettere la nuova regione della mappa.


3

So che questa è una vecchia domanda ma, se vuoi visualizzare tutte le annotazioni GIÀ SULLA mappa usa questo:

 mapView.showAnnotations(mapView.annotations, animated: true)

3

Ecco l'equivalente SWIFT (lavoro confermato in: Xcode6.1, SDK 8.2) per le risposte di 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)

}

1
Ehi iOS_Developer. Grazie per la conversione Swift. Per me non funziona perché penso che ti manchino due "fmax" invece di "fmin" per topLeftCoordinate.latitude e bottomRightCoordinate.longitude.
Philipp Otto

2

Una possibile soluzione potrebbe essere la misurazione della distanza tra la posizione corrente e tutte le annotazioni e l'utilizzo del metodo MKCoordinateRegionMakeWithDistance per creare una regione con una distanza leggermente maggiore rispetto all'annotazione più lontana.

Questo ovviamente diventerebbe più lento con il maggior numero di annotazioni aggiunte.


Stavo esaminando la sezione dei commenti solo per convalidare me stesso. Sono contento che qualcun altro la pensi come me :-) Dato che ho aggiunto solo due annotazioni (punto iniziale e punto finale), non ho sentito alcuna lentezza.
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];
}

2

Basato sull'eccellente risposta di me2(ora in 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)
}

1

Aggiunta una piccola clausola if per gestire 1 posizione, da aggiungere allo snippet di codice di mustufa. Utilizzata la funzione zoomToAnnotation di pkclSoft per questo:

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
}

1

questo codice funziona per me, mostra tutti i pin con la posizione corrente, spero che questo ti aiuti,

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)

}

0

Spero che questo sia almeno rilevante, questo è quello che ho messo insieme per Mono (basato sulla risposta di 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); 
}

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

0

Sulla base della risposta di me2 ho scritto una categoria per MKMapView per aggiungere alcuni margini e saltare l'annotazione della posizione dell'utente:

@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

0

Dato che non posso commentare una risposta, vorrei aggiungere un po 'di comodità alla risposta di @ me2 (poiché pensavo fosse l'approccio più elegante trovato qui).

Per il mio progetto personale ho semplicemente aggiunto una categoria sulla classe MKMapView per incapsulare la funzionalità "area visibile" per un'operazione molto comune: impostazione per poter vedere tutte le annotazioni attualmente caricate sull'istanza MKMapView. il risultato è stato questo:

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

Come puoi vedere, finora ho aggiunto 2 metodi: uno per impostare la regione visibile della mappa su quella che si adatta a tutte le annotazioni attualmente caricate sull'istanza MKMapView e un altro metodo per impostarla su qualsiasi array di oggetti. Quindi, per impostare la regione visibile di mapView, il codice sarebbe semplice come:

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

Spero che aiuti =)


0

Considera questa estensione:

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

0

Una rapida versione 5:

   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)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.