Zoomen von MKMapView, um Anmerkungsstifte anzupassen?


193

Ich verwende MKMapView und habe der Karte eine Reihe von Anmerkungsstiften über einen Bereich von 5 bis 10 Kilometern hinzugefügt. Wenn ich die Anwendung starte, wird meine Karte verkleinert, um die ganze Welt anzuzeigen. Wie kann ich die Karte am besten zoomen, damit die Stifte in die Ansicht passen?

BEARBEITEN: Mein erster Gedanke wäre, MKCoordinateRegionMake zu verwenden und das Koordinatenzentrum, longitudeDelta und latitudeDelta aus meinen Anmerkungen zu berechnen. Ich bin mir ziemlich sicher, dass dies funktionieren wird, aber ich wollte nur überprüfen, ob mir etwas Offensichtliches fehlt.

Code hinzugefügt, BTW: FGLocation ist eine Klasse, die konform ist MKAnnotation, locationFake ist eines NSMutableArraydieser Objekte. Kommentare sind immer willkommen ....

- (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
Hinweis für iOS 7: Mit der neuen Methode showAnnotations: animiert: können Sie diese manuelle Regionsberechnung vermeiden.

Antworten:


123

Du hast es richtig gemacht.

Finden Sie Ihre maximalen und minimalen Breiten- und Längengrade, wenden Sie eine einfache Arithmetik an und verwenden Sie sie MKCoordinateRegionMake.

Für iOS 7 und höher, die Verwendung showAnnotations:animated:von 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
Für iOS 7 und höher (unter Bezugnahme auf 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
Dies funktioniert gut, aber gelegentlich, wenn ich (in der Karte) zoome und dann versuche, es zu zentrieren (mithilfe einer Schaltfläche, die diese Methode aufruft), scheint es nicht zu funktionieren.
RPM

5
Es ist wichtig zu beachten, dass showAnnotationsdie Anmerkungen auch zur Karte hinzugefügt werden, selbst wenn bereits eine Anmerkung für diesen Ort vorhanden ist.
Eneko Alonso

@EnekoAlonso Sie können dies umgehen, indem Sie removeAnnotations(_ annotations:)sofort nachshowAnnotations(_ annotations:animated)
Alain Stulz

1
Erwähnenswert ist auch, dass showAnnotations den Bereich so festlegt, dass Anmerkungen angezeigt werden, der Bereich jedoch weiterhin an das Seitenverhältnis angepasst wird. und dies schließt häufig einige der Anmerkungen aus. Beachten Sie auch, dass showAnnotations die einzig richtige Lösung ist, die hier vorgestellt wird. Keine der anderen Antworten versucht, Anmerkungen zu verarbeiten, die sich über die internationale Datumsgrenze erstrecken.
Gordon Dove

335

Dies ist die, die ich hier gefunden habe und die für mich funktioniert hat:

(BEARBEITEN: Ich habe die Lösung mit dem Vorschlag von @ Micah aktualisiert, den pointRect um 0,1 zu erhöhen, um sicherzustellen, dass der Rect nicht unendlich klein wird!)

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

 

Sie können dies auch aktualisieren, um den userLocation-Pin einzuschließen, indem Sie die erste Zeile durch Folgendes ersetzen:

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

4
Tatsächlich nett. Sie müssen isNull jedoch nicht überprüfen. MKMapRectUnion erledigt dies für Sie. Aus den Dokumenten: "Wenn eines der Rechtecke null ist, gibt diese Methode das andere Rechteck zurück."
Felix Lamouroux

37
Sehr schöne Lösung !!! Hier ist eine zusätzliche kleine Berührung, um etwas Polsterung hinzuzufügen: double inset = -zoomRect.size.width * 0.1; [self.mapView setVisibleMapRect: MKMapRectInset (zoomRect, inset, inset) animiert: YES];
Craig B

1
Genial! Mögliche Ergänzung: Wenn Sie die 'aktuelle Standortanmerkung' ausschließen möchten, fügen Sie einfach eine if-Anweisung in die for-Schleife ein: if (! [Anmerkung isKindOfClass: [MKUserLocation-Klasse]]) {// Hier Sachen machen}
kgaidis

2
Die @ CraigB-Lösung zum Auffüllen ist ausgezeichnet, funktioniert jedoch nicht gut, wenn der Pfad vertikal ist, z. B. Bewegung von Süden nach Norden. Um dies zu beheben, verwenden Sie den doppelten Einschub = MIN (-zoomRect.size.width * 0.1, -zoomRect.size. Höhe * 0,1);
Farhad Malekpour

1
Erweiterung durch Auffüllen: double insetWidth = -zoomRect.size.width * 0.2; double insetHeight = -zoomRect.size.height * 0.2; MKMapRect insetRect = MKMapRectInset (zoomRect, insetWidth, insetHeight); Dann verwenden Sie diese neue insertRect
Dulgan

121

Apple hat eine neue Methode für IOS 7 hinzugefügt, um das Leben ein wenig zu vereinfachen.

[mapView showAnnotations:yourAnnotationArray animated:YES];

Sie können ganz einfach aus einem in der Kartenansicht gespeicherten Array ziehen:

yourAnnotationArray = mapView.annotations;

und schnell auch die Kamera einstellen!

mapView.camera.altitude *= 1.4;

Dies funktioniert nur, wenn auf dem Benutzer iOS 7+ oder OS X 10.9+ installiert ist. Schauen Sie sich hier die benutzerdefinierte Animation an


Ich bin mir nicht sicher, ob dies auf einige andere Faktoren in meiner Implementierung zurückzuführen ist, aber ich finde, dass showAnnotationsdas Zoomen / Anpassen der Anmerkungen nicht so eng ist wie bei der manuellen Implementierung, daher habe ich mich an die manuelle gehalten.
Ted Avery

1
Versuchen Sie, die Höhe der Kamera mit einem Bruchteil von eins zu multiplizieren, z. B. mapView.camera.altitude * = .85; für ein näheres Ansichtsfenster
Ryan Berg

Ich fand dies auch nützlich, um Anmerkungen außerhalb des aktuell sichtbaren Kartenbereichs auszuwählen. Standardmäßig wählt MapView keine nicht sichtbaren Anmerkungen aus. Rufen Sie showAnnotations mit einem Array Ihrer nicht sichtbaren Anmerkungen auf, bevor Sie selectAnnotation aufrufen, und die Karte sollte ihren sichtbaren Bereich aktualisieren.
MandisaW

42

Ich benutze diesen Code und funktioniert gut für mich:

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

Arbeiten Sie nicht für: ▿ 2 Elemente ▿ 0: CLLocationCoordinate2D - Breitengrad: 46.969995730376894 - Längengrad: -109.2494943434474 ▿ 1: CLLocationCoordinate2D - Breitengrad: 63.23212154333072 - Längengrad: 174.13666611126533
Olexiy Pyovov

23

Im Swift-Einsatz

mapView.showAnnotations(annotationArray, animated: true)

In Ziel c

[mapView showAnnotations:annotationArray animated:YES];

2
Wenn die Anmerkungen bereits in der mapView festgelegt wurden, können Sie sie direkt referenzieren mit:mapView.showAnnotations(mapView.annotations, animated: true)
Justin Vallely

14

Ich habe die Antwort von Rafael Moreira konvertiert. Der Kredit geht an ihn. Für diejenigen unter Ihnen, die nach der Swift-Version suchen, ist hier der Code:

 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 Dies ist die richtige Methode, um alle Anmerkungen in die Karte einzupassen.

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 Ihre vorgeschlagene Bearbeitung wurde abgelehnt. Wenn Sie eine neue Antwort für Swift 4.2 bereitstellen möchten, können Sie diese gerne als Antwort hinzufügen, nicht indem Sie sie in einem anderen Benutzerbeitrag bearbeiten.
Nick

13

@ jowies Lösung funktioniert großartig. Ein Haken: Wenn eine Karte nur eine Anmerkung enthält, erhalten Sie eine vollständig herausgezoomte Karte. Ich habe der Rect-Make-Größe 0,1 hinzugefügt, um sicherzustellen, dass setVisibleMapRect etwas zum Zoomen hat.

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

12

Wenn Sie nach iOS 8 und höher suchen , ist es am einfachsten, var layoutMargins: UIEdgeInsets { get set }die Kartenansicht vor dem Anruf festzulegenfunc showAnnotations(annotations: [MKAnnotation], animated: Bool)

Zum Beispiel (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

Ich habe eine Erweiterung erstellt, um alle Anmerkungen mit etwas Code von hier und da in Kürze anzuzeigen. Dies zeigt nicht alle Anmerkungen an, wenn sie auch bei maximaler Zoomstufe nicht angezeigt werden können.

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

Durch Ändern der UIEdgeInsetsMakeParameter konnte ich bessere Ergebnisse erzielen . Werte zwischen 30 und 100 waren gut für mich. Ich habe mit dem iPhone SE i) S 10.2 Simulator getestet. Beispielcode : setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(100, 100, 100, 100), animated: true). Dieser Code funktioniert in Swift 3 und XCode 8.2.1.
Nyxee

8

Diese If-Schleife innerhalb der for-Schleife wurde hinzugefügt, um den Standort-Pin des Benutzers von dieser Methode auszuschließen (in meinem Fall erforderlich, und möglicherweise auch in anderen).

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

//Code Here...

}

8

Für iOS 7 und höher (siehe 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);

Bemerkung von - Abhishek Bedi

Sie rufen einfach an:

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

Nur als Referenz war der Text NS_AVAILABLE enthalten, da im Januar 2011 iOS 7 auf einem Gerät nicht sehr wahrscheinlich war und NS_AVAILABLE die App vor Build-Fehlern oder Abstürzen schützte.
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)

// Bearbeitet für Swift 5


4

Dank jowie habe ich meine alte Kategorie auf eine elegantere Lösung aktualisiert. Teilen Sie die vollständige, fast kopier- und einfügebereite Lösung

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

Hoffe es hilft jemandem und danke nochmal 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

Wie Abhishek Bedi in einem Kommentar betont, ist für iOS7 Forward der beste Weg, dies zu tun ,:

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

Für mein persönliches Projekt (vor iOS7) habe ich der MKMapView-Klasse einfach eine Kategorie hinzugefügt, um die Funktionalität "Sichtbarer Bereich" für eine sehr häufige Operation zu kapseln: Festlegen, dass alle aktuell geladenen Anmerkungen in der MKMapView-Instanz angezeigt werden ( Dies umfasst so viele Pins, wie Sie möglicherweise platziert haben, sowie den Standort des Benutzers. 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 den Bereich, der 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 =)


3

Bei allen Antworten auf dieser Seite wird davon ausgegangen, dass die Karte den Vollbildmodus einnimmt . Ich habe tatsächlich eine HUD-Anzeige (dh Schaltflächen, die oben und unten verstreut sind), die Informationen auf der Karte anzeigen. Daher zeigen die Algorithmen auf der Seite die Stifte in Ordnung an, aber einige davon werden unter den Schaltflächen der HUD-Anzeige angezeigt .

Meine Lösung zoomt die Karte heran, um die Anmerkungen in einer Teilmenge des Bildschirms anzuzeigen, und funktioniert für verschiedene Bildschirmgrößen (z. B. 3,5 "gegenüber 4,0" usw.):

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

Folgendes habe ich im Code getan (Hinweis: Ich verwende NSConstraintseinige Hilfsmethoden, um meinen Code in verschiedenen Bildschirmgrößen arbeiten zu lassen. Während der Code gut lesbar ist. Meine Antwort hier erklärt es besser. Es ist im Grunde der gleiche Workflow :)

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

Hier ist der Code, der die Region erhält, die passt:

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

Ich habe Rafaels Code für die MKMapView-Kategorie ein wenig geändert.

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

Basierend auf den obigen Antworten können Sie die Karte mithilfe der universellen Methode zoomen, um alle Anmerkungen und Überlagerungen gleichzeitig anzupassen.

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

Und dann:

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

Ich teile nur meine Beobachtungen dazu:

Wenn Sie xCode> 6 mit "abgeleiteten" Größen für die Bildschirme (siehe "simulierte Metriken" im Dateiinspektor) im Storyboard verwenden, rufen Sie auf

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

In viewDidLoadführt bei iPhones mit 4 Zoll zu einer zu großen Zoomstufe, da das Layout für die Karte immer noch der Größe der breiteren Bildschirme des Storyboards entspricht.

Sie können Ihren Anruf showAnnotations...nach verschieben viewDidAppear. Dann wurde die Größe der Karte bereits an den kleineren Bildschirm eines iPhone 4 angepasst.

Oder ändern Sie alternativ den Wert "abgeleitet" im Dateiinspektor unter "simulierte Metriken" in "iPhone 4-Zoll".


1

Sie können auswählen, welche Formen Sie zusammen mit den Anmerkungen anzeigen möchten.

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

@ "Ich bin nicht sicher, ob dies auf einige andere Faktoren in meiner Implementierung zurückzuführen ist, aber ich finde, dass showAnnotations das Zoomen / Anpassen der Anmerkungen nicht so genau bewirkt wie die manuelle Implementierung, daher habe ich mich an die gehalten Handbuch eins. - Ted Avery 17. April um 0:35 "

Ich hatte das gleiche Problem, aber dann habe ich zweimal versucht, showAnnotations zu machen (wie unten), und aus irgendeinem Grund hat es funktioniert.

[mapView showAnnotations: yourAnnotationArray animiert: YES]; [mapView showAnnotations: yourAnnotationArray animiert: YES];


0

Eine iOS 7-kompatible Methode besteht darin, Folgendes zu verwenden. Rufen Sie zuerst showAnnotationauf, um ein Rechteck mit allen Anmerkungen zu erhalten. Anschließend erstellen und UIEdgeInsetmit einem oberen Einsatz der Stifthöhe. So stellen Sie sicher, dass der gesamte Pin auf der Karte angezeigt wird.

[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

Fügen Sie dies entsprechend in Ihren Code ein:

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

       [mv setRegion:region animated:YES];

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