Zoom MKMapView per adattarsi ai pin di annotazione?


193

Sto usando MKMapView e ho aggiunto un numero di pin di annotazione alla mappa su un'area di 5-10 chilometri. Quando eseguo l'applicazione la mia mappa inizia a rimpicciolire per mostrare tutto il mondo, qual è il modo migliore per ingrandire la mappa in modo che i pin si adattino alla vista?

EDIT: Il mio pensiero iniziale sarebbe di usare MKCoordinateRegionMake e calcolare il centro di coordinate, la longitudine Delta e la latitudine Delta dalle mie annotazioni. Sono abbastanza sicuro che funzionerà, ma volevo solo controllare che non mi mancasse nulla di ovvio.

Codice aggiunto, BTW: FGLocation è una classe conforme MKAnnotation, locationFake è uno NSMutableArraydi questi oggetti. I commenti sono sempre ben accetti ....

- (MKCoordinateRegion)regionFromLocations {
    CLLocationCoordinate2D upper = [[locationFake objectAtIndex:0] coordinate];
    CLLocationCoordinate2D lower = [[locationFake objectAtIndex:0] coordinate];

    // FIND LIMITS
    for(FGLocation *eachLocation in locationFake) {
        if([eachLocation coordinate].latitude > upper.latitude) upper.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].latitude < lower.latitude) lower.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].longitude > upper.longitude) upper.longitude = [eachLocation coordinate].longitude;
        if([eachLocation coordinate].longitude < lower.longitude) lower.longitude = [eachLocation coordinate].longitude;
    }

    // FIND REGION
    MKCoordinateSpan locationSpan;
    locationSpan.latitudeDelta = upper.latitude - lower.latitude;
    locationSpan.longitudeDelta = upper.longitude - lower.longitude;
    CLLocationCoordinate2D locationCenter;
    locationCenter.latitude = (upper.latitude + lower.latitude) / 2;
    locationCenter.longitude = (upper.longitude + lower.longitude) / 2;

    MKCoordinateRegion region = MKCoordinateRegionMake(locationCenter, locationSpan);
    return region;
}

10
Nota per iOS 7: il nuovo metodo showAnnotations: animato: può aiutarti a evitare questo calcolo manuale della regione.

Risposte:


123

Hai capito bene.

Trova le tue latitudini e lunghezze massime e minime, applica un po 'di aritmetica semplice e usa MKCoordinateRegionMake.

Per iOS 7 e versioni successive, utilizzare showAnnotations:animated:, da MKMapView.h:

// Position the map such that the provided array of annotations are all visible to the fullest extent possible. 
- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

158
Per iOS 7 e versioni successive (riferendosi a MKMapView.h): // Position the map such that the provided array of annotations are all visible to the fullest extent possible. - (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);
Abhishek Bedi

1
Funziona bene ma a volte quando ingrandisco (nella mappa) quindi provo a centrarlo (usando un pulsante che invoca questo metodo) non sembra funzionare.
RPM,

5
È importante notare che showAnnotationsaggiunge anche le annotazioni alla mappa, anche se esiste già un'annotazione per quella posizione.
Eneko Alonso,

@EnekoAlonso Puoi aggirare il problema chiamando removeAnnotations(_ annotations:)subito doposhowAnnotations(_ annotations:animated)
Alain Stulz,

1
Vale anche la pena notare che mentre showAnnotations imposta la regione per visualizzare le annotazioni, la regione viene comunque regolata per adattarsi alle proporzioni; e questo esclude spesso alcune delle annotazioni. Si noti inoltre che showAnnotations è l'unica soluzione corretta presentata qui; nessuna delle altre risposte tenta nemmeno di gestire le annotazioni che coprono la linea della data internazionale.
Gordon Dove,

335

Questo è quello che ho trovato qui che ha funzionato per me:

(EDIT: ho aggiornato la soluzione usando il suggerimento di @Micah per aumentare il puntoRect di 0,1 per garantire che il retto non finisca per essere infinitamente piccolo!)

MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapView.annotations)
{
    MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapView setVisibleMapRect:zoomRect animated:YES];

 

Puoi anche aggiornare questo per includere il pin userLocation sostituendo la prima riga con:

MKMapPoint annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
MKMapRect zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

4
Davvero bello. Non è necessario selezionare isNull però. MKMapRectUnion fa questo per te. Dai documenti: "Se uno dei rettangoli è null, questo metodo restituisce l'altro rettangolo."
Felix Lamouroux,

37
Ottima soluzione !!! Ecco un tocco in più per aggiungere un po 'di imbottitura: double inset = -zoomRect.size.width * 0.1; [self.mapView setVisibleMapRect: MKMapRectInset (zoomRect, inserto, inserto) animato: SÌ];
Craig B,

1
Eccezionale! Aggiunta potenziale: se si desidera escludere l '"annotazione della posizione corrente", aggiungere semplicemente un'istruzione if nel ciclo for: if (! [Annotation isKindOfClass: [MKUserLocation class]]) {// Fai le cose qui}
kgaidis

2
La soluzione @CraigB per l'imbottitura è eccellente, ma non funziona bene quando il percorso è verticale, ad es. Movimento da sud a nord, per risolvere questo problema utilizzare double inset = MIN (-zoomRect.size.width * 0.1, -zoomRect.size. altezza * 0,1);
Farhad Malekpour,

1
Miglioramento con imbottitura: double insetWidth = -zoomRect.size.width * 0.2; double insetHeight = -zoomRect.size.height * 0.2; MKMapRect insetRect = MKMapRectInset (zoomRect, insetWidth, insetHeight); Quindi utilizzare questo nuovo insertRect
dulgan il

121

Apple ha aggiunto un nuovo metodo per IOS 7 per semplificare un po 'la vita.

[mapView showAnnotations:yourAnnotationArray animated:YES];

Puoi facilmente estrarre da un array memorizzato nella vista mappa:

yourAnnotationArray = mapView.annotations;

e regola rapidamente anche la fotocamera!

mapView.camera.altitude *= 1.4;

questo non funzionerà a meno che l'utente non abbia iOS 7+ o OS X 10.9+ installati. controlla qui l' animazione personalizzata


Non sono sicuro che ciò sia dovuto ad alcuni altri fattori nella mia implementazione, ma trovo che showAnnotationsnon si avvicini allo zoom / adattamento delle annotazioni come fa l'implementazione manuale, quindi mi sono bloccato con quello manuale.
Ted Avery,

1
prova a moltiplicare l'altitudine delle telecamere per una frazione di una, come mapView.camera.altitude * = .85; per una visione più ravvicinata
Ryan Berg,

Ho anche trovato questo utile per selezionare le annotazioni al di fuori dell'area della mappa visibile corrente. Per impostazione predefinita, MapView non seleziona annotazioni non visibili. Chiama showAnnotations con un array delle tue annotazioni non visibili, prima di chiamare selectAnnotation, e la mappa dovrebbe aggiornare la sua area visualizzabile.
MandisaW

42

Uso questo codice e funziona bene per me:

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

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

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

    for(MapViewAnnotation *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;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    region = [aMapView regionThatFits:region];
    [mapView setRegion:region animated:YES];
}

Non lavoro per: ▿ 2 elementi ▿ 0: CLLocationCoordinate2D - latitudine: 46,969995730376894 - longitudine: -109,2494943434474 ▿ 1: CLLocationCoordinate2D - latitudine: 63,23212154333072 - longitudine: 174,13666611126533
Olexiy Pyvovarov

23

In Swift usare

mapView.showAnnotations(annotationArray, animated: true)

Nell'obiettivo c

[mapView showAnnotations:annotationArray animated:YES];

2
Se le annotazioni sono già state impostate su mapView, puoi fare riferimento direttamente a:mapView.showAnnotations(mapView.annotations, animated: true)
Justin Vallely

14

Ho convertito la risposta di Rafael Moreira. Il merito va a lui. Per quelli di voi che cercano la versione Swift, ecco il codice:

 func zoomToFitMapAnnotations(aMapView: MKMapView) {
    guard aMapView.annotations.count > 0 else {
        return
    }
    var topLeftCoord: CLLocationCoordinate2D = CLLocationCoordinate2D()
    topLeftCoord.latitude = -90
    topLeftCoord.longitude = 180
    var bottomRightCoord: CLLocationCoordinate2D = CLLocationCoordinate2D()
    bottomRightCoord.latitude = 90
    bottomRightCoord.longitude = -180
    for annotation: MKAnnotation in myMap.annotations as! [MKAnnotation]{
        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)
    }

    var region: MKCoordinateRegion = MKCoordinateRegion()
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.4
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.4
    region = aMapView.regionThatFits(region)
    myMap.setRegion(region, animated: true)
}

14

Swift 3 Questo è il modo corretto per adattarsi a tutte le annotazioni nella mappa.

func zoomMapaFitAnnotations() {

        var zoomRect = MKMapRectNull
        for annotation in mapview.annotations {

            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)

            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0)

            if (MKMapRectIsNull(zoomRect)) {
                zoomRect = pointRect
            } else {
                zoomRect = MKMapRectUnion(zoomRect, pointRect)
            }
        }
        self.mapview.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(50, 50, 50, 50), animated: true)

    }

@ArshadShaik La modifica suggerita è stata rifiutata, se desideri fornire una nuova risposta per Swift 4.2, sentiti libero, ma aggiungilo come risposta, non modificandolo nel post di un altro utente.
Nick,

13

La soluzione di @ jowie funziona alla grande. Una cattura, se una mappa ha solo un'annotazione, finirai con una mappa completamente ridotta. Ho aggiunto 0.1 a rect make size per assicurarmi che setVisibleMapRect abbia qualcosa su cui zoomare.

MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

12

Se stai cercando iOS 8 e versioni successive , il modo più semplice per farlo è impostare la visualizzazione var layoutMargins: UIEdgeInsets { get set }della mappa prima di chiamarefunc showAnnotations(annotations: [MKAnnotation], animated: Bool)

Ad esempio (Swift 2.1):

@IBOutlet weak var map: MKMapView! {
    didSet {
        map.delegate = self
        map.mapType = .Standard
        map.pitchEnabled = false
        map.rotateEnabled = false
        map.scrollEnabled = true
        map.zoomEnabled = true
    }
}

// call 'updateView()' when viewWillAppear or whenever you set the map annotations
func updateView() {
    map.layoutMargins = UIEdgeInsets(top: 25, left: 25, bottom: 25, right: 25)
    map.showAnnotations(map.annotations, animated: true)
}

12

Ho creato un'estensione per mostrare tutte le annotazioni usando un po 'di codice da qui e lì in fretta. Questo non mostrerà tutte le annotazioni se non possono essere mostrate nemmeno al massimo livello di zoom.

import MapKit

extension MKMapView {
    func fitAllAnnotations() {
        var zoomRect = MKMapRectNull;
        for annotation in annotations {
            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
            zoomRect = MKMapRectUnion(zoomRect, pointRect);
        }
        setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50), animated: true)
    }
}

Sono riuscito a ottenere risultati migliori modificando i UIEdgeInsetsMakeparametri, i valori tra 30 e 100 sono stati buoni per me. Stavo testando con iPhone SE i) S 10.2 Simulator. Codice di esempio: setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(100, 100, 100, 100), animated: true). Come nota, questo codice funziona in Swift 3 e XCode 8.2.1.
Nyxee,

8

Aggiunto questo ciclo If all'interno del ciclo for per escludere il pin posizione dell'utente da questo metodo (richiesto nel mio caso, e forse altri)

if (![annotation isKindOfClass:[MKUserLocation class]] ) {

//Code Here...

}

8

Per iOS 7 e versioni successive (riferendosi a MKMapView.h):

// Position the map such that the provided array of annotations are all visible to the fullest extent possible.          

- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

osservazione da - Abhishek Bedi

Basta chiamare:

 [yourMapView showAnnotations:@[yourAnnotation] animated:YES];

Solo per riferimento, il testo NS_AVAILABLE era lì perché a gennaio 2011, avere iOS 7 su un dispositivo non era molto probabile e NS_AVAILABLE ha protetto l'app da errori di build o crash.
Matthew Frederick,

5

In Swift

    var zoomRect = MKMapRectNull;

    for i in 0..<self.map.annotations.count {

        let annotation: MKAnnotation = self.map.annotations[i]

        let annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }

    self.map.setVisibleMapRect(zoomRect, animated: true)

5
    var zoomRect: MKMapRect = MKMapRect.null
    for annotation in mapView.annotations {
        let annotationPoint = MKMapPoint(annotation.coordinate)
        let pointRect = MKMapRect(x: annotationPoint.x, y: annotationPoint.y, width: 0.1, height: 0.1)
        zoomRect = zoomRect.union(pointRect)
    }
    mapView.setVisibleMapRect(zoomRect, animated: true)

// Modificato per swift 5


4

Grazie a Jowie ho aggiornato la mia vecchia categoria a una soluzione più elegante. Condivisione della soluzione completa, quasi copia e incolla pronta

MKMapView + AnnotationsRegion.h

#import <MapKit/MapKit.h>

@interface MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated;
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated;
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

@end

MKMapView + AnnotationsRegion.m

#import "MKMapView+AnnotationsRegion.h"

@implementation MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated{
    [self updateRegionForCurrentAnnotationsAnimated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    [self updateRegionForAnnotations:self.annotations animated:animated edgePadding:edgePadding];
}

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated{
    [self updateRegionForAnnotations:annotations animated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    MKMapRect zoomRect = MKMapRectNull;
    for(id<MKAnnotation> annotation in annotations){
        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }
    [self setVisibleMapRect:zoomRect edgePadding:edgePadding animated:animated];
}

@end

Spero che aiuti qualcuno e grazie ancora jowie!


4
 - (void)zoomMapViewToFitAnnotationsWithExtraZoomToAdjust:(double)extraZoom
{

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

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

   for (id<MKAnnotation> annotation in [self annotations])
  {
      points[i++] = MKMapPointForCoordinate(annotation.coordinate);
   }

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

MKCoordinateRegion r = MKCoordinateRegionForMapRect([poly boundingMapRect]);
r.span.latitudeDelta += extraZoom;
r.span.longitudeDelta += extraZoom;

[self setRegion: r animated:YES];

}

4

Come sottolinea Abhishek Bedi in un commento, per iOS7 in avanti il ​​modo migliore per farlo è:

//from API docs: 
//- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);
[self.mapView showAnnotations:self.mapView.annotations animated:YES];

Per il mio progetto personale (prima di iOS7) ho semplicemente aggiunto una categoria sulla classe MKMapView per incapsulare la funzionalità "area visibile" per un'operazione molto comune: impostarla in modo da poter vedere tutte le annotazioni attualmente caricate sull'istanza MKMapView ( questo include tutti i pin che potresti aver inserito, così come la posizione dell'utente). il risultato è stato questo:

.h file

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

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


@end

.m file

#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, ho aggiunto finora 2 metodi: uno per impostare l'area visibile della mappa su quella che si adatta a tutte le annotazioni attualmente caricate sull'istanza MKMapView e un altro metodo per impostarlo 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 =)


3

Tutte le risposte in questa pagina presuppongono che la mappa occupi lo schermo intero . In realtà ho un display HUD (ovvero pulsanti sparsi in alto e in basso) che forniscono informazioni in cima alla mappa .. e quindi gli algoritmi sulla pagina mostreranno i pin bene, ma alcuni di essi appariranno sotto i pulsanti del display HUD .

La mia soluzione ingrandisce la mappa per visualizzare le annotazioni in un sottoinsieme dello schermo e funziona con schermi di dimensioni diverse (es. 3,5 "vs 4,0" ecc.):

// create a UIView placeholder and throw it on top of the original mapview
// position the UIView to fit the maximum area not hidden by the HUD display buttons
// add an *other* mapview in that uiview, 
// get the MKCoordinateRegion that fits the pins from that fake mapview
// kill the fake mapview and set the region of the original map 
// to that MKCoordinateRegion.

Ecco cosa ho fatto nel codice (nota: utilizzo NSConstraintscon alcuni metodi di supporto per far funzionare il mio codice in diverse dimensioni dello schermo .. mentre il codice è abbastanza leggibile .. la mia risposta qui lo spiega meglio .. è fondamentalmente lo stesso flusso di lavoro :)

// position smallerMap to fit available space
// don't store this map, it will slow down things if we keep it hidden or even in memory
[@[_smallerMapPlaceholder] mapObjectsApplyingBlock:^(UIView *view) {
    [view removeFromSuperview];
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
    [view setHidden:NO];
    [self.view addSubview:view];
}];

NSDictionary *buttonBindingDict = @{ @"mapPlaceholder": _smallerMapPlaceholder};

NSArray *constraints = [@[@"V:|-225-[mapPlaceholder(>=50)]-176-|",
                          @"|-40-[mapPlaceholder(<=240)]-40-|"
                          ] mapObjectsUsingBlock:^id(NSString *formatString, NSUInteger idx){
                              return [NSLayoutConstraint constraintsWithVisualFormat:formatString options:0 metrics:nil views:buttonBindingDict];
                          }];

[self.view addConstraints:[constraints flattenArray]];
[self.view layoutIfNeeded];

MKMapView *smallerMap = [[MKMapView alloc] initWithFrame:self.smallerMapPlaceholder.frame];
[_smallerMapPlaceholder addSubview:smallerMap];

MKCoordinateRegion regionThatFits = [smallerMap getRegionThatFits:self.mapView.annotations];
[smallerMap removeFromSuperview];
smallerMap = nil;
[_smallerMapPlaceholder setHidden:YES];

[self.mapView setRegion:regionThatFits animated:YES];

ecco il codice che ottiene l'area adatta:

- (MKCoordinateRegion)getRegionThatFits:(NSArray *)routes {
    MKCoordinateRegion region;
    CLLocationDegrees maxLat = -90.0;
    CLLocationDegrees maxLon = -180.0;
    CLLocationDegrees minLat = 90.0;
    CLLocationDegrees minLon = 180.0;
    for(int idx = 0; idx < routes.count; idx++)
    {
        CLLocation* currentLocation = [routes objectAtIndex:idx];
        if(currentLocation.coordinate.latitude > maxLat)
            maxLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.latitude < minLat)
            minLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.longitude > maxLon)
            maxLon = currentLocation.coordinate.longitude;
        if(currentLocation.coordinate.longitude < minLon)
            minLon = currentLocation.coordinate.longitude;
    }
    region.center.latitude     = (maxLat + minLat) / 2.0;
    region.center.longitude    = (maxLon + minLon) / 2.0;
    region.span.latitudeDelta = 0.01;
    region.span.longitudeDelta = 0.01;

    region.span.latitudeDelta  = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
    region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);

    MKCoordinateRegion regionThatFits = [self regionThatFits:region];
    return regionThatFits;
}

2

Ho apportato una piccola modifica al codice di Rafael per la categoria MKMapView.

- (void)zoomToFitMapAnnotations {
    if ([self.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 self.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;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    [self setRegion:[self regionThatFits:region] animated:YES];
}

2

In base alle risposte precedenti puoi utilizzare il metodo universale per ingrandire la mappa in modo da adattare tutte le annotazioni e le sovrapposizioni contemporaneamente.

-(MKMapRect)getZoomingRectOnMap:(MKMapView*)map toFitAllOverlays:(BOOL)overlays andAnnotations:(BOOL)annotations includeUserLocation:(BOOL)userLocation {
    if (!map) {
        return MKMapRectNull;
    }

    NSMutableArray* overlaysAndAnnotationsCoordinateArray = [[NSMutableArray alloc]init];        
    if (overlays) {
        for (id <MKOverlay> overlay in map.overlays) {
            MKMapPoint overlayPoint = MKMapPointForCoordinate(overlay.coordinate);
            NSArray* coordinate = @[[NSNumber numberWithDouble:overlayPoint.x], [NSNumber numberWithDouble:overlayPoint.y]];
            [overlaysAndAnnotationsCoordinateArray addObject:coordinate];
        }
    }

    if (annotations) {
        for (id <MKAnnotation> annotation in map.annotations) {
            MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
            NSArray* coordinate = @[[NSNumber numberWithDouble:annotationPoint.x], [NSNumber numberWithDouble:annotationPoint.y]];
            [overlaysAndAnnotationsCoordinateArray addObject:coordinate];
        }
    }

    MKMapRect zoomRect = MKMapRectNull;
    if (userLocation) {
        MKMapPoint annotationPoint = MKMapPointForCoordinate(map.userLocation.coordinate);
        zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    }

    for (NSArray* coordinate in overlaysAndAnnotationsCoordinateArray) {
        MKMapRect pointRect = MKMapRectMake([coordinate[0] doubleValue], [coordinate[1] doubleValue], 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }

    return zoomRect;
}

E poi:

MKMapRect mapRect = [self getZoomingRectOnMap:mapView toFitAllOverlays:YES andAnnotations:YES includeUserLocation:NO];
[mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0) animated:YES];

1

Sto solo condividendo le mie osservazioni su questo:

Se stai usando xCode> 6 con dimensioni "inferite" per le schermate (vedi "metriche simulate" nella finestra di ispezione dei file) nello storyboard, chiamando

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

in viewDidLoadsi tradurrà in un livello di zoom troppo grande su iPhone con 4 pollici perché il layout per la mappa è ancora sulla dimensione degli schermi più ampi dello storyboard.

Puoi spostare la chiamata showAnnotations...a viewDidAppear. Quindi la dimensione della mappa è già stata adattata allo schermo più piccolo di un iPhone 4.

Oppure, in alternativa, modifica il valore "inferito" nella finestra di ispezione dei file in "metriche simulate" in iPhone da 4 pollici.


1

Puoi selezionare quali forme vuoi mostrare insieme alle Annotazioni.

extension MKMapView {
  func setVisibleMapRectToFitAllAnnotations(animated: Bool = true,
                                            shouldIncludeUserAccuracyRange: Bool = true,
                                            shouldIncludeOverlays: Bool = true,
                                            edgePadding: UIEdgeInsets = UIEdgeInsets(top: 35, left: 35, bottom: 35, right: 35)) {
    var mapOverlays = overlays

    if shouldIncludeUserAccuracyRange, let userLocation = userLocation.location {
      let userAccuracyRangeCircle = MKCircle(center: userLocation.coordinate, radius: userLocation.horizontalAccuracy)
      mapOverlays.append(MKOverlayRenderer(overlay: userAccuracyRangeCircle).overlay)
    }

    if shouldIncludeOverlays {
      let annotations = self.annotations.filter { !($0 is MKUserLocation) }
      annotations.forEach { annotation in
        let cirlce = MKCircle(center: annotation.coordinate, radius: 1)
        mapOverlays.append(cirlce)
      }
    }

    let zoomRect = MKMapRect(bounding: mapOverlays)
    setVisibleMapRect(zoomRect, edgePadding: edgePadding, animated: animated)
  }
}

extension MKMapRect {
  init(bounding overlays: [MKOverlay]) {
    self = .null
    overlays.forEach { overlay in
      let rect: MKMapRect = overlay.boundingMapRect
      self = self.union(rect)
    }
  }
}

0

@ "Non sono sicuro che ciò sia dovuto ad altri fattori nella mia implementazione, ma trovo che showAnnotations non esegua lo zoom / adattamento delle annotazioni come l'implementazione manuale, quindi mi sono bloccato con il uno manuale. - Ted Avery, 17 aprile alle 0:35 "

Ho avuto lo stesso problema, ma poi ho provato a fare showAnnotations due volte (come sotto) e per qualche motivo ha funzionato.

[mapView showAnnotations: yourAnnotationArray animato: SÌ]; [mapView showAnnotations: yourAnnotationArray animato: SÌ];


0

Un modo compatibile con iOS 7 consiste nell'utilizzare quanto segue. Prima chiamata showAnnotationper ottenere un rettangolo contenente tutte le annotazioni. Successivamente creare e UIEdgeInsetcon un inserto superiore dell'altezza del perno. In questo modo ti assicuri di mostrare l'intero perno sulla mappa.

[self.mapView showAnnotations:self.mapView.annotations animated:YES];
MKMapRect rect = [self.mapView visibleMapRect];
UIEdgeInsets insets = UIEdgeInsetsMake(pinHeight, 0, 0, 0);
[self.mapView setVisibleMapRect:rect edgePadding:insets animated:YES];

0

Inseriscilo nel tuo codice di conseguenza:

  - (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
    {
    id<MKAnnotation> mp = [annotationView annotation];
        MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,250,250);

       [mv setRegion:region animated:YES];

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