Einstellen der Zoomstufe für eine MKMapView


118

Ich habe eine Karte, die korrekt angezeigt wird. Jetzt möchte ich nur noch die Zoomstufe beim Laden einstellen. Gibt es eine Möglichkeit, dies zu tun?

Vielen Dank

Antworten:


198

Ich habe eine Lösung gefunden, die sehr einfach ist und den Trick macht. Verwenden Sie diese MKCoordinateRegionMakeWithDistanceOption, um den Abstand in Metern vertikal und horizontal einzustellen und den gewünschten Zoom zu erzielen. Und wenn Sie dann Ihren Standort aktualisieren, erhalten Sie natürlich die richtigen Koordinaten, oder Sie können sie direkt CLLocationCoordinate2Dbeim Start angeben , wenn Sie dies tun müssen:

CLLocationCoordinate2D noLocation;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];          
[self.mapView setRegion:adjustedRegion animated:YES];
self.mapView.showsUserLocation = YES;

Schnell:

let location = ...
let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: CLLocationDistance(exactly: 5000)!, longitudinalMeters: CLLocationDistance(exactly: 5000)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)

3
Dies sollte die ausgewählte Antwort sein. Ich habe viele der anderen vorgeschlagenen Lösungen ausprobiert, aber keine davon hat richtig funktioniert. Dieser Code ist einfach und effektiv.
Levi Roberts

1
Gute Antwort. Der Zoom ist jedoch je nach Bildschirmgröße unterschiedlich, oder?
Vinzius

1
Interessanterweise gibt MKCoordinateRegionMakeWithDistancees noch in Swift. Diese Lösung funktioniert!
LinusGeffarth

47

Basierend auf der Tatsache, dass Längengradlinien an jedem Punkt der Karte gleichmäßig voneinander beabstandet sind, gibt es eine sehr einfache Implementierung, um centerCoordinate und zoomLevel festzulegen:

@interface MKMapView (ZoomLevel)

@property (assign, nonatomic) NSUInteger zoomLevel;

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated;

@end


@implementation MKMapView (ZoomLevel)

- (void)setZoomLevel:(NSUInteger)zoomLevel {
    [self setCenterCoordinate:self.centerCoordinate zoomLevel:zoomLevel animated:NO];
}

- (NSUInteger)zoomLevel {
    return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1;
}

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
    MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
    [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}

@end

Kleinere Korrekturen:- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated { MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256); [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated]; }
Monobono

Vielen Dank! Ja, Sie haben Recht, ich habe den Code tatsächlich aus meinem Projekt entfernt, wo er eher eine Funktion als eine Ergänzung zu MKMapView war. Ich habe gerade den Code bearbeitet, um Ihre Korrektur widerzuspiegeln.
Quentinadam

1
Was ist die Umkehrung dieser Formel, um die aktuelle Zoomstufe zu ermitteln?
Nick

1
Ich denke, es ist das:double z = log2(360 * ((self.mapView.frame.size.width/256) / self.mapView.region.span.longitudeDelta));
Nick

1
@devios, bei Zoomstufe 1 passt die ganze Welt (360 °) in 1 Kachel mit einer Breite von 256 Pixel. Bei Zoomstufe 2 passt die ganze Welt (360 °) in 2 Kacheln mit 256 Pixel (512 Pixel). Bei Zoomstufe 3 passt die ganze Welt (360 °) in 4 Kacheln mit 256 Pixel (1024 Pixel) usw.
Quentinadam

31

Es ist nicht eingebaut, aber ich habe diesen Code gesehen / verwendet . Dies ermöglicht Ihnen Folgendes:

[mapView setCenterCoordinate:myCoord zoomLevel:13 animated:YES];

Hinweis: Dies ist nicht mein Code, ich habe ihn nicht geschrieben und kann ihn daher nicht gutschreiben


1
Wow, es ist viel Code, du würdest denken, es sollte eingebaut sein. Danke. Ich werde einen Blick darauf werfen, wie es gemacht wird.
System

1
Sie können die Dateien .m und .h abrufen, sie Ihrem Projekt hinzufügen, sie dann in Ihrem Kartenansichts-Controller referenzieren und sie so verwenden, als wäre sie eine Methode in MKMapView, oh, die Freude an Kategorien!
PostMan

2
Hat bei mir nicht funktioniert, es zeigt nur die gleiche Zoomstufe wie zuvor an. Ich muss etwas falsch machen.
System

17

Sie können auch zoomen, indem Sie MKCoordinateRegion verwenden und das Delta für Breite, Breite und Länge einstellen. Unten finden Sie eine Kurzreferenz und hier die iOS-Referenz. Es macht nichts Besonderes, sollte es Ihnen aber ermöglichen, den Zoom beim Zeichnen der Karte einzustellen.


MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
mapView.region = region;

Bearbeiten 1:

MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:TRUE];

1
Dies machte für mich keinen Unterschied, wenn ich einige Werte ändere, wird die Karte einfach nicht geladen.
System

Stellen Sie dies ein, wenn die Karte geladen wird, oder versuchen Sie zu manipulieren, nachdem das Laden stattgefunden hat? Verwenden Sie 1 oder eine kleinere Zahl als Deltas? Ich versuche nur, die Anforderungen zu verstehen.
DerekH

Ich habe es vor der Laufzeit eingestellt. Ich habe Werte über und unter 1 getestet.
System

1
Gute Antwort, aber versuchen Sie, Breiten- und Längengraddelta auf 0,1 zu ändern - es wird mehr gezoomt.
Daniel Krzyczkowski

12

Eine einfache Swift-Implementierung, wenn Sie Steckdosen verwenden.

@IBOutlet weak var mapView: MKMapView! {
    didSet {
        let noLocation = CLLocationCoordinate2D()
        let viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500)
        self.mapView.setRegion(viewRegion, animated: false)
    }
}

Basierend auf der Antwort von @ Carnal.


12

Schnelle Implementierung

import Foundation
import MapKit

class MapViewWithZoom: MKMapView {

    var zoomLevel: Int {
        get {
            return Int(log2(360 * (Double(self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1);
        }

        set (newZoomLevel){
            setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
        }
    }

    private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool) {
        let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, Double(zoomLevel)) * Double(self.frame.size.width) / 256)
        setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
    }
}

1
Ich bin nicht 100% sicher, aber ich denke, wenn Sie Ihre IBOutletzu Ihrer erstellen map, definieren Sie es als eine MapViewWithZoomanstelle einer einfachen MKMapView. Dann können Sie einfach die map.zoomLevel = 1map.zoomLevel = 0.5
Zoomstufe

1
Einige Kommentare dazu wären hilfreicher. Es funktioniert in Swift 3.
Nyxee

Tolle Lösung! Aber ich mag es eher als Erweiterung, und es gibt eine seltsame Sache: Um tatsächlich herauszuzoomen, muss man um 2 wie dekrementierenmapView.zoomLevel -= 2
Alexander

7

Für Swift 3 ist es ziemlich schnell vorwärts:

private func setMapRegion(for location: CLLocationCoordinate2D, animated: Bool)
{
    let viewRegion = MKCoordinateRegionMakeWithDistance(location, <#T##latitudinalMeters: CLLocationDistance##CLLocationDistance#>, <#T##longitudinalMeters: CLLocationDistance##CLLocationDistance#>)
    MapView.setRegion(viewRegion, animated: animated)
}

Definieren Sie einfach die Lat-, Long-Meter <CLLocationDistance>und die mapView passt die Zoomstufe an Ihre Werte an.


Was meinst du mit "die mapView passt die Zoomstufe an deine Werte an"? Ich gehe davon aus, dass das OP die Zoomstufe selbst einstellen möchte, oder wie würden Sie dies angesichts der von Ihnen vorgeschlagenen Eingabe tun?
Riper

6

Basierend auf der großartigen Antwort von @ AdilSoomro . Ich habe mir Folgendes ausgedacht:

@interface MKMapView (ZoomLevel)
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated;

-(double) getZoomLevel;
@end



@implementation MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
    MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
    [self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}


-(double) getZoomLevel {
    return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta));
}

@end

3

Ich hoffe, das folgende Codefragment würde Ihnen helfen.

- (void)handleZoomOutAction:(id)sender {
    MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.s       pan.latitudeDelta/0.5, mapView.region.span.longitudeDelta/0.5));
    [mapView setRegion:newRegion];
}


- (void)handleZoomInAction:(id)sender {
    MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.span.latitudeDelta*0.5, mapView.region.span.longitudeDelta*0.5));
    [mapView setRegion:newRegion];
}

Sie können einen beliebigen Wert anstelle von 0,5 wählen, um die Zoomstufe zu verringern oder zu erhöhen. Ich habe diese Methoden beim Klicken auf zwei Schaltflächen verwendet.


2

Eine Swift 2.0-Antwort mit NSUserDefaults zum Speichern und Wiederherstellen des Zooms und der Position der Karte.

Funktion zum Speichern der Kartenposition und zum Zoomen:

func saveMapRegion() {
    let mapRegion = [
        "latitude" : mapView.region.center.latitude,
        "longitude" : mapView.region.center.longitude,
        "latitudeDelta" : mapView.region.span.latitudeDelta,
        "longitudeDelta" : mapView.region.span.longitudeDelta
    ]
    NSUserDefaults.standardUserDefaults().setObject(mapRegion, forKey: "mapRegion")
}

Führen Sie die Funktion jedes Mal aus, wenn die Karte verschoben wird:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) 
{
        saveMapRegion();
}

Funktion zum Speichern des Kartenzooms und der Position:

func restoreMapRegion() 
{
    if let mapRegion = NSUserDefaults.standardUserDefaults().objectForKey("mapRegion") 
    {

        let longitude = mapRegion["longitude"] as! CLLocationDegrees
        let latitude = mapRegion["latitude"] as! CLLocationDegrees
        let center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

        let longitudeDelta = mapRegion["latitudeDelta"] as! CLLocationDegrees
        let latitudeDelta = mapRegion["longitudeDelta"] as! CLLocationDegrees
        let span = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)

        let savedRegion = MKCoordinateRegion(center: center, span: span)

        self.mapView.setRegion(savedRegion, animated: false)
    }
}

Fügen Sie dies zu viewDidLoad hinzu:

restoreMapRegion()

1

Ich weiß, dass dies eine späte Antwort ist, aber ich wollte nur das Problem der Einstellung der Zoomstufe selbst ansprechen. Die Antwort von Goldmine ist großartig, aber ich fand, dass sie in meiner Bewerbung nicht gut genug funktioniert.

Bei näherer Betrachtung stellt Goldmine fest, dass "Längengrade an jedem Punkt der Karte gleich weit voneinander entfernt sind". Dies ist nicht wahr, es sind tatsächlich Breitengradlinien, die gleichmäßig von -90 (Südpol) bis +90 (Nordpol) beabstandet sind. Längengradlinien sind am Äquator am breitesten beabstandet und konvergieren zu einem Punkt an den Polen.

Die Implementierung, die ich übernommen habe, besteht daher darin, die Breitengradberechnung wie folgt zu verwenden:

@implementation MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate
    zoomLevel:(NSUInteger)zoom animated:(BOOL)animated
{
    MKCoordinateSpan span = MKCoordinateSpanMake(180 / pow(2, zoom) * 
        self.frame.size.height / 256, 0);
    [self setRegion:MKCoordinateRegionMake(coordinate, span) animated:animated];
}

@end

Hoffe, es hilft in diesem späten Stadium.


Ok, ignoriere das oben. Goldmine ist korrekt, die Längengrade sind gleichmäßig verteilt, da natürlich die Mercator-Projektion für die Karten verwendet wird. Meine Probleme mit der Lösung resultierten aus einem weiteren kleinen Fehler in meiner Anwendung, der mit der Unterklasse der neuen iOS 7 MKTileOverlay-Klasse zusammenhängt.
Gektron

Möglicherweise möchten Sie Ihren Beitrag aktualisieren, um die Informationen wiederzugeben, die Sie in Ihrem Kommentar enthalten haben.
Derek Lee

1

Schnell:

Map.setRegion(MKCoordinateRegion(center: locValue, latitudinalMeters: 200, longitudinalMeters: 200), animated: true)

locValue ist Ihre Koordinate.


1

Hier stelle ich meine Antwort und ihre Arbeit für schnelle 4.2 .

MKMapView zentrieren und vergrößern


Wenn ich hier klicke und nach unten scrolle und dort auf Ihren Link klicke, werde ich mich hier wiederfinden und dann hier klicken und jetzt stecke ich in einer Endlosschleife fest Matth
Matthijs

@Matthijs Ich habe den Link korrigiert. Bitte überprüfen und stimmen Sie die Antwort ab.
Ashu

0

Basierend auf der Antwort von Quentinadam

Swift 5.1

// size refers to the width/height of your tile images, by default is 256.0
// Seems to get better results using round()
// frame.width is the width of the MKMapView

let zoom = round(log2(360 * Double(frame.width) / size / region.span.longitudeDelta))

Danke, sieht gut aus, wenn die Karte nach Norden zeigt. Aber was ist, wenn Sie die Karte drehen? Was ist, wenn der Quetschwinkel von 0 abweicht?
pierre23

0

MKMapViewErweiterung basierend auf dieser Antwort (+ Genauigkeit der Gleitkommazoomstufe):

import Foundation
import MapKit

extension MKMapView {
    var zoomLevel: Double {
        get {
            return log2(360 * (Double(self.frame.size.width / 256) / self.region.span.longitudeDelta)) + 1
        }

        set (newZoomLevel){
            setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
        }
    }

    private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Double, animated: Bool) {
        let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, zoomLevel) * Double(self.frame.size.width) / 256)
        setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
    }
}
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.