Positionieren Sie MKMapView so, dass mehrere Anmerkungen gleichzeitig angezeigt werden


92

Ich habe mehrere Anmerkungen, die ich zu meiner MKMapView hinzufügen möchte (es können 0-n Elemente sein, wobei n im Allgemeinen bei 5 liegt). Ich kann die Anmerkungen gut hinzufügen, aber ich möchte die Größe der Karte so ändern, dass alle Anmerkungen gleichzeitig auf dem Bildschirm angezeigt werden, und ich bin mir nicht sicher, wie ich das tun soll.

Ich habe es -regionThatFits:mir angesehen, bin mir aber nicht ganz sicher, was ich damit anfangen soll. Ich werde einen Code posten, um zu zeigen, was ich bisher habe. Ich denke, dies sollte eine allgemein einfache Aufgabe sein, aber ich fühle mich bisher ein bisschen mit MapKit überfordert.

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

Beachten Sie, dass dies alles passiert, wenn ich ein Standortupdate erhalte ... Ich weiß nicht, ob dies ein geeigneter Ort dafür ist. Wenn nicht, wo wäre ein besserer Ort? -viewDidLoad?

Danke im Voraus.

Antworten:



137

Der von Jim gepostete Link ist jetzt tot, aber ich konnte den Code finden (den ich irgendwo mit einem Lesezeichen versehen hatte). Hoffe das hilft.

- (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
Ich könnte dich küssen. Das hat mir nur ein bisschen Zeit gespart. Ich habe den Code oben hinzugefügt, um 1 Position zu behandeln. Es wurde ein wenig nah und persönlich. Ich werde das als Antwort posten, da Kommentare dazu neigen, Code zu zerkauen.
Michael Reed

Vielen Dank. Ich habe dies zu einer Unterklasse von hinzugefügt MKMapViewund die Methode in geändert - (void) zoomToFitAnnotations:(BOOL)animated. Funktioniert perfekt!
Simonbs

1
es funktioniert sehr gut. es ist auch nützlich. Sie können den Verkleinerungs- oder Vergrößerungswert ändern. also region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; /// Wert ändern. Wenn Sie den Wert erhöhen: Verkleinern ........ Wenn Sie den Wert verringern: Vergrößern, zum Beispiel: region.span.latitudeDelta = fabs (topLeftCoord.latitude - bottomRightCoord.latitude) * 4.1;
Erhan Demirci

1
@ MR.Mustafa: Es funktioniert, super! Aber ich denke nicht, dass die Lösung des Problems ausreicht. Also bitte erklärt mir jemand, wie es funktioniert. Oder über irgendwelche Links. Tut mir leid, wenn ich dumm bin, ich bin ein Anfänger. Bitte unterstützen. Vielen Dank
Siddarth Hagelsturm

1
@ Mustafa ... Danke, es hat meinen Tag gerettet.
Vvk

133

Warum so kompliziert?

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
Unglaublich, wie viel einfacher, sauberer und einfacher dies ist als die veröffentlichten Alternativen. Sie können dies sogar noch weiter vereinfachen, da keine Konvertierung in MKCoordinateRegion erforderlich ist. Rufen Sie einfach setVisibleMapRect: in Ihrem MKMapView mit dem hier erstellten MKMapRect auf.
Lensovet

2
Die Anmerkungen bleiben manchmal oben auf der Karte hängen und sind nicht sichtbar. Gibt es eine Eingabe zum besten Ansatz zum Erhöhen des Zooms nach dem Erstellen der MKCoordinateRegion?
Kyle C

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

Wie erstellen Sie das CLLocationCoordinate2D *coordsArray? Verwenden malloc()?
Hlung

3
@ KyleC. Ich habe dies hinzugefügt, bevor ich rCGFloat 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));
zurückkam,

44

Ich habe etwas Ähnliches getan, um einen Bereich zu verkleinern (oder zu vergrößern), der eine Punktanmerkung und den aktuellen Standort enthält. Sie können dies erweitern, indem Sie Ihre Anmerkungen durchlaufen.

Die grundlegenden Schritte sind:

  • Berechnen Sie die min lat / long
  • Berechnen Sie die maximale Lat / Long
  • Erstellen Sie CLLocation-Objekte für diese beiden Punkte
  • Berechnen Sie den Abstand zwischen Punkten
  • Erstellen Sie eine Region mit dem Mittelpunkt zwischen Punkten und der Entfernung in Grad
  • Übergeben Sie die Region zum Anpassen an MapView
  • Verwenden Sie die angepasste Region, um die MapView-Region festzulegen
    -(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];
    }

Dies scheint der richtige Weg zu sein. Vielen Dank!
Jbrennan

1
Managed bekommen diese mit zu arbeiten MKCoordinateRegionMake: gist.github.com/1599700 falls jemand noch will es auf diese Weise zu tun.
Chakrit

region.center.latitude = (Südwestlatitude + Nordostlatitude) / 2.0; Danke dafür
Tony

Funktioniert dies mit Punkten auf beiden Seiten des Meridians? Der Equator?
Eliot

1
Dieser Code platziert die Standorte außerhalb des Bildschirms, wenn die Standorte einen ähnlichen y-Wert haben. Wenn Sie beispielsweise zwei Positionen bei (50, -4) und (100, -3) anzeigen, wird die Karte zu weit gezoomt, wobei die Koordinaten links und rechts vom Bildschirm platziert werden.
Benutzer

21

Ich habe eine andere Antwort. Ich wollte den Zoom-to-Fit-Algorithmus selbst implementieren, aber ich dachte mir, dass Apple eine Möglichkeit haben muss , das zu tun, was wir wollten, ohne so viel Arbeit. Die Verwendung des API-Dokuments zeigte schnell, dass ich MKPolygon verwenden konnte, um das zu tun, was benötigt wurde:

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

Hoffe das hilft.


Keine Probleme. Es gibt normalerweise einen besseren Weg, wenn Sie bereit sind und die Zeit haben, sich damit zu beschäftigen.
PKCLsoft

Ich habe festgestellt, dass die Stifte dadurch etwas zu nahe am Bildschirmrand platziert werden. Versuchen Sie, annotationsRegion.span.latitudeDelta = annotationsRegion.span.latitudeDelta * kEventMapDetailBorderFactor hinzuzufügen. kurz vor der setRegion.
Adam Eberbach

Sie haben Recht @AdamEberbach, aber es scheint, dass Ihr Clip eine Konstante enthält, die nicht verfügbar ist. Haben Sie einen Wert gefunden, der einen "schönen" Rand um die Stifte bietet?
PKCLsoft

Die Antwort von Code Commander über die Verwendung der neuen showAnnotations-Methode mit iOS7 fügt einen schönen Rand hinzu, der tatsächlich besser funktioniert, obwohl dieser Code cooler ist.
James Toomey

14

Sie können es auch so machen ..

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

Basierend auf den Informationen und Vorschlägen von allen habe ich Folgendes gefunden. Vielen Dank für alle in dieser Diskussion für ihren Beitrag :) Dies würde in den View Controller gehen, der die mapView enthält.

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

Dies sollte mehr Stimmen bekommen. Sehr präzise und auf den Punkt.
Natasha

5

In meinem Fall beginne ich mit CLLocation-Objekten und erstelle Anmerkungen für jedes dieser Objekte.
Ich muss nur zwei Anmerkungen platzieren, daher habe ich einen einfachen Ansatz zum Erstellen des Array von Punkten, aber es könnte leicht erweitert werden, um ein Array mit einer beliebigen Länge bei einer Reihe von CLLocations zu erstellen.

Hier ist meine Implementierung (es ist nicht erforderlich, MKMapPoints zu erstellen):

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

Mit Swift, einem Polygon und einigen zusätzlichen Auffüllungen habe ich Folgendes verwendet:

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 (...). Ich habe selbst nachgerechnet ... schlecht.
CodeReaper

3

Ab 'iOS 7 gibt es in' MKMapView 'eine neue Methode, die Sie verwenden können

Erklärung

SCHNELL

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

ZIEL C

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

Parameter

Anmerkungen Die Anmerkungen, die in der Karte angezeigt werden sollen. animiert JA, wenn die Änderung der Kartenregion animiert werden soll, oder NEIN, wenn die Karte die neue Region sofort ohne Animationen anzeigen soll.

Diskussion

Durch Aufrufen dieser Methode wird der Wert in der Region-Eigenschaft und möglicherweise anderen Eigenschaften aktualisiert, um die neue Kartenregion widerzuspiegeln.


3

Ich weiß, dass dies eine alte Frage ist, aber wenn Sie alle Anmerkungen BEREITS auf der Karte anzeigen möchten, verwenden Sie Folgendes:

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

3

Hier ist das SWIFT-Äquivalent (Bestätigtes Arbeiten in: Xcode6.1, SDK 8.2) für Mustafas Antworten:

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
Hey iOS_Developer. Danke für die schnelle Umstellung. Für mich funktioniert es nicht, weil ich denke, dass Ihnen zwei "fmax" anstelle von "fmin" für topLeftCoordinate.latitude und bottomRightCoordinate.longitude fehlen.
Philipp Otto

2

Eine mögliche Lösung könnte darin bestehen, den Abstand zwischen dem aktuellen Standort und allen Anmerkungen zu messen und mithilfe der MKCoordinateRegionMakeWithDistance-Methode einen Bereich zu erstellen, der einen etwas größeren Abstand als die am weitesten entfernte Anmerkung aufweist.

Dies würde natürlich langsamer werden, je mehr Anmerkungen Sie hinzugefügt haben.


Ich habe den Kommentarbereich nur durchgesehen, um mich selbst zu bestätigen. Ich bin froh, dass jemand anderes so denkt wie ich :-) Da ich nur zwei Anmerkungen (Anfangs- und Endpunkt) hinzufüge, habe ich keine Langsamkeit gespürt.
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

Basierend auf der hervorragenden Antwort von me2(jetzt 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

Es wurde eine kleine if-Klausel hinzugefügt, um 1 Speicherort zu behandeln - um das Cound-Code-Snippet von Mustufa zu ergänzen. Verwendete die zoomToAnnotation-Funktion von pkclSoft dafür:

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

Dieser Code funktioniert für mich. Er zeigt alle Pins mit der aktuellen Position an. Ich hoffe, das hilft Ihnen.

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

Ich hoffe, das ist zumindest relevant, das habe ich für Mono zusammengestellt (basierend auf der Antwort von 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

Basierend auf der Antwort von me2 habe ich eine Kategorie für MKMapView geschrieben, um einige Ränder hinzuzufügen und Anmerkungen zum Benutzerstandort zu überspringen:

@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

Da ich eine Antwort nicht kommentieren kann, möchte ich der Antwort von @ me2 ein wenig Bequemlichkeit hinzufügen (da ich dachte, es sei der eleganteste Ansatz, der hier zu finden ist).

Für mein persönliches Projekt habe ich der MKMapView-Klasse einfach eine Kategorie hinzugefügt, um die Funktion "Sichtbarer Bereich" für eine sehr häufige Operation zu kapseln: Einstellung, um alle aktuell geladenen Anmerkungen in der MKMapView-Instanz anzeigen zu können. Das Ergebnis war:

.h Datei

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

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


@end

.m Datei

#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

Wie Sie sehen, habe ich bisher zwei Methoden hinzugefügt: eine zum Festlegen des sichtbaren Bereichs der Karte auf diejenige, die für alle aktuell geladenen Anmerkungen in der MKMapView-Instanz geeignet ist, und eine andere Methode zum Festlegen eines beliebigen Arrays von Objekten. Um den sichtbaren Bereich von mapView festzulegen, wäre der Code so einfach wie:

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

Ich hoffe es hilft =)


0

Betrachten Sie diese Erweiterung:

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

Eine schnelle 5-Version:

   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)
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.