Menyetel level zoom untuk MKMapView

118

Saya memiliki peta yang menunjukkan dengan benar, satu-satunya hal yang ingin saya lakukan sekarang adalah menyetel tingkat zoom saat dimuat. Apakah ada cara untuk melakukan ini?

Terima kasih

sistem
sumber

Jawaban:

198

Saya menemukan solusi untuk diri saya sendiri, yang sangat sederhana dan berhasil. Gunakan MKCoordinateRegionMakeWithDistanceuntuk mengatur jarak dalam meter secara vertikal dan horizontal untuk mendapatkan zoom yang diinginkan. Dan tentu saja ketika Anda memperbarui lokasi Anda, Anda akan mendapatkan koordinat yang tepat, atau Anda dapat menentukannya langsung di CLLocationCoordinate2Dsaat startup, jika itu yang perlu Anda lakukan:

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

Cepat:

let location = ...
let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: CLLocationDistance(exactly: 5000)!, longitudinalMeters: CLLocationDistance(exactly: 5000)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)
Jasmani
sumber
3
Ini harus menjadi jawaban yang dipilih. Saya mencoba banyak solusi lain yang diusulkan tetapi tidak ada yang berfungsi dengan baik. Kode ini sederhana dan efektif.
Levi Roberts
1
Jawaban bagus. Bagaimanapun zoom akan berbeda tergantung pada ukuran layar, bukan?
Vinzius
1
Menariknya, MKCoordinateRegionMakeWithDistancemasih ada di Swift. Solusi ini berhasil!
LinusGeffarth
47

Berdasarkan fakta bahwa garis bujur diberi jarak yang sama pada titik mana pun di peta, terdapat implementasi yang sangat sederhana untuk menyetel centerCoordinate dan zoomLevel:

@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
quentinadam
sumber
Koreksi kecil:- (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
Terima kasih! Ya Anda benar, saya benar-benar mengeluarkan kode dari proyek saya di mana itu adalah fungsi daripada tambahan untuk MKMapView. Saya baru saja mengedit kode untuk mencerminkan koreksi Anda.
quentinadam
1
Apa kebalikan dari rumus itu, untuk menghitung tingkat zoom saat ini?
Nick
1
Saya pikir ini:double z = log2(360 * ((self.mapView.frame.size.width/256) / self.mapView.region.span.longitudeDelta));
Nick
1
@devios, pada tingkat zoom 1, seluruh dunia (360 °) muat dalam 1 ubin dengan lebar 256 piksel. Pada tingkat zoom 2, seluruh dunia (360 °) cocok dalam 2 ubin 256px (512px). Pada tingkat zoom 3, seluruh dunia (360 °) muat dalam 4 ubin 256 piksel (1024 piksel), dll.
quentinadam
31

Itu tidak ada di dalamnya, tetapi saya telah melihat / menggunakan kode ini . Ini memungkinkan Anda untuk menggunakan ini:

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

Catatan: Ini bukan kode saya, saya tidak menulisnya, jadi karena itu tidak dapat mengambil kredit untuk itu

Tukang pos
sumber
1
wow, ini banyak kodenya, kamu akan berpikir itu harus dibangun. terima kasih. akan melihat bagaimana ini dilakukan.
sistem
1
Anda bisa mendapatkan file .m dan .h, menambahkannya ke proyek Anda, kemudian mereferensikannya di pengontrol tampilan peta Anda, dan menggunakannya seolah-olah itu adalah metode di MKMapView, oh nikmatnya kategori!
PostMan
2
Tidak berfungsi untuk saya, ini hanya menampilkan tingkat zoom yang sama seperti sebelumnya. Saya pasti melakukan sesuatu yang salah.
sistem
17

Anda juga dapat memperbesar dengan menggunakan MKCoordinateRegion dan mengatur rentang lintang & bujur delta. Di bawah ini adalah referensi cepat dan di sini adalah referensi iOS. Itu tidak akan melakukan sesuatu yang mewah tetapi harus memungkinkan Anda untuk mengatur zoom saat menggambar peta.


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

Edit 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];
DerekH
sumber
1
Ini tidak membuat perbedaan bagi saya, ketika saya mengubah beberapa nilai, itu tidak memuat peta.
sistem
Apakah Anda menyetel ini ketika peta dimuat atau Anda mencoba memanipulasi setelah pemuatan dilakukan? Apakah Anda menggunakan 1 atau angka yang lebih kecil sebagai delta Anda? Hanya mencoba memahami persyaratannya.
DerekH
Saya mengaturnya sebelum runtime. Saya menguji nilai di atas dan di bawah 1.
sistem
1
Jawaban bagus tapi coba ubah lintang, delta bujur menjadi 0,1 - itu lebih diperbesar.
Daniel Krzyczkowski
12

Implementasi Swift sederhana, jika Anda menggunakan outlet.

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

Berdasarkan jawaban @ Carnal.

swennemen
sumber
12

Implementasi yang cepat

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)
    }
}
Vlad Spreys
sumber
1
Saya tidak 100% yakin, tapi saya rasa ketika Anda membuat milik IBOutletAnda sendiri map, Anda mendefinisikannya sebagai MapViewWithZoombukan yang sederhana MKMapView. Kemudian, Anda dapat mengatur level zoom dengan map.zoomLevel = 1ataumap.zoomLevel = 0.5
Zonker.in.Geneva
1
beberapa komentar tentang ini akan lebih membantu. Ini bekerja di Swift 3.
nyxee
Solusi bagus! Tapi saya lebih menyukainya sebagai Perpanjangan, dan ada satu hal yang aneh: untuk benar-benar memperkecil, perlu mengurangi 2 sukamapView.zoomLevel -= 2
Alexander
7

Untuk Swift 3 ini cukup cepat:

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

Cukup tentukan Lat-, long-Meter <CLLocationDistance>dan mapView akan menyesuaikan tingkat zoom dengan nilai Anda.

zero3nna
sumber
Apa yang Anda maksud dengan "mapView akan menyesuaikan tingkat zoom dengan nilai Anda"? Saya berasumsi OP ingin mengatur sendiri tingkat zoom atau bagaimana Anda melakukannya dengan masukan yang Anda sarankan?
riper
6

Berdasarkan jawaban hebat @ AdilSoomro . Saya telah menemukan ini:

@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
Nick
sumber
3

Saya harap potongan kode berikut akan membantu Anda.

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

Anda dapat memilih nilai apa pun sebagai ganti 0,5 untuk mengurangi atau meningkatkan level zoom. Saya telah menggunakan metode ini dengan mengklik dua tombol.

dispatchMain
sumber
2

Jawaban Swift 2.0 yang memanfaatkan NSUserDefaults untuk menyimpan dan memulihkan zoom dan posisi peta.

Fungsi untuk menyimpan posisi peta dan zoom:

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

Jalankan fungsinya setiap kali peta dipindahkan:

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

Fungsi untuk menyimpan zoom dan posisi peta:

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

Tambahkan ini ke viewDidLoad:

restoreMapRegion()
David T
sumber
1

Saya tahu ini adalah jawaban yang terlambat, tetapi saya hanya ingin mengatasi masalah pengaturan tingkat zoom sendiri. Jawaban goldmine bagus tetapi saya merasa tidak berfungsi dengan baik dalam aplikasi saya.

Pada pemeriksaan lebih dekat, tambang emas menyatakan bahwa "garis bujur memiliki jarak yang sama di setiap titik peta". Ini tidak benar, sebenarnya garis lintang yang diberi jarak yang sama dari -90 (kutub selatan) hingga +90 (kutub utara). Garis bujur diberi jarak terlebar di ekuator, menyatu ke satu titik di kutub.

Oleh karena itu, implementasi yang saya adopsi adalah dengan menggunakan perhitungan garis lintang sebagai berikut:

@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

Semoga membantu pada tahap akhir ini.

gektron
sumber
Ok abaikan yang diatas. Tambang emas benar, garis bujur ADALAH spasi yang sama karena tentu saja proyeksi Mercator digunakan untuk peta. Masalah saya dengan solusinya berasal dari bug minor lain dalam aplikasi saya yang berkaitan dengan subclass kelas iOS 7 MKTileOverlay baru.
gektron
Anda mungkin ingin mempertimbangkan untuk memperbarui posting Anda untuk mencerminkan informasi yang Anda masukkan dalam komentar Anda.
Derek Lee
1

Cepat:

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

locValue adalah koordinat Anda.

waktu.
sumber
1

Di sini, saya meletakkan jawaban saya dan bekerja untuk 4.2 cepat .

Pusat MKMapView dan perbesar

Ashu
sumber
Jika saya mengklik di sini dan menggulir ke bawah, dan mengklik tautan Anda di sana, saya akan menemukan diri saya di sini lagi dan kemudian saya klik di sini dan sekarang saya terjebak dalam lingkaran tak terbatas 😏
Matthijs
@Matthijs Saya telah mengoreksi tautannya. Silakan periksa dan pilih jawabannya.
Ashu
0

Berdasarkan jawaban quentinadam

Swift 5.1.0

// 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))
vauxhall
sumber
Terima kasih, terlihat bagus saat peta menghadap ke Utara. Tetapi bagaimana jika Anda memutar peta? Bagaimana jika sudut jepit berbeda dari 0?
pierre23
0

MKMapViewekstensi berdasarkan jawaban ini (+ akurasi tingkat zoom floating-point):

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)
    }
}
Marcin Piela
sumber