การตั้งค่าระดับการซูมสำหรับ MKMapView


118

ฉันมีแผนที่ที่แสดงอย่างถูกต้องสิ่งเดียวที่ฉันต้องการทำตอนนี้คือตั้งระดับการซูมเมื่อโหลด มีวิธีทำไหม?

ขอบคุณ

คำตอบ:


200

ฉันพบวิธีแก้ปัญหาด้วยตัวเองซึ่งทำได้ง่ายมาก ใช้MKCoordinateRegionMakeWithDistanceเพื่อกำหนดระยะทางเป็นเมตรในแนวตั้งและแนวนอนเพื่อให้ได้การซูมที่ต้องการ และแน่นอนเมื่อคุณอัปเดตตำแหน่งของคุณคุณจะได้รับพิกัดที่ถูกต้องหรือคุณสามารถระบุได้โดยตรงในCLLocationCoordinate2Dตอนเริ่มต้นหากนั่นคือสิ่งที่คุณต้องทำ:

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

สวิฟท์:

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

3
นี่ควรเป็นคำตอบที่เลือก ฉันลองใช้วิธีแก้ปัญหาที่เสนออื่น ๆ มากมาย แต่ไม่มีวิธีใดทำงานได้อย่างถูกต้อง รหัสนี้ง่ายและมีประสิทธิภาพ
Levi Roberts

1
คำตอบที่ดี อย่างไรก็ตามการซูมจะแตกต่างกันขึ้นอยู่กับขนาดหน้าจอไม่ใช่เหรอ?
Vinzius

1
ที่น่าสนใจMKCoordinateRegionMakeWithDistanceยังคงอยู่ใน Swift วิธีนี้ใช้ได้ผล!
LinusGeffarth

47

จากข้อเท็จจริงที่ว่าเส้นลองจิจูดมีระยะห่างเท่า ๆ กันที่จุดใด ๆ ของแผนที่มีการใช้งานที่ง่ายมากในการตั้งค่า centerCoordinate และ 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

การแก้ไขเล็กน้อย:- (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]; }
โมโนโบโน

ขอบคุณ! ใช่คุณพูดถูกจริงๆแล้วฉันเอาโค้ดออกจากโปรเจ็กต์ของฉันโดยที่มันเป็นฟังก์ชั่นแทนที่จะเพิ่ม MKMapView ฉันเพิ่งแก้ไขเป็นรหัสเพื่อแสดงการแก้ไขของคุณ
quentinadam

1
การย้อนกลับของสูตรนั้นคืออะไรในการคำนวณระดับการซูมปัจจุบัน
นิค

1
ฉันคิดว่ามันคือ:double z = log2(360 * ((self.mapView.frame.size.width/256) / self.mapView.region.span.longitudeDelta));
นิค

1
@devios ที่ระดับการซูม 1 โลกทั้งใบ (360 °) จะพอดีกับกระเบื้อง 1 แผ่นที่มีความกว้าง 256px ที่ระดับการซูม 2 โลกทั้งใบ (360 °) จะมีขนาด 256px (512px) 2 แผ่น ที่ระดับการซูม 3 โลกทั้งใบ (360 °) จะพอดีกับ 4 แผ่นขนาด 256px (1024px) เป็นต้น
quentinadam

31

มันไม่ได้ในตัว แต่ผมเคยเห็น / ใช้นี้รหัส สิ่งนี้ช่วยให้คุณใช้สิ่งนี้:

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

หมายเหตุ: นี่ไม่ใช่รหัสของฉันฉันไม่ได้เขียนไว้ดังนั้นจึงไม่สามารถรับเครดิตได้


1
ว้าวรหัสเยอะมากคุณคิดว่ามันควรจะมีอยู่แล้วขอบคุณ จะมีลักษณะเป็นอย่างไร
ระบบ

1
คุณสามารถรับไฟล์. m และ. h เพิ่มลงในโปรเจ็กต์ของคุณจากนั้นอ้างอิงในตัวควบคุมมุมมองแผนที่ของคุณและใช้มันราวกับว่ามันเป็นวิธีการบน MKMapView โอ้ความสุขของหมวดหมู่!
PostMan

2
ไม่ได้ผลสำหรับฉันมันก็แสดงระดับการซูมเหมือนเดิม ฉันต้องทำอะไรผิดแน่ ๆ
ระบบ

17

คุณยังสามารถซูมได้โดยใช้ MKCoordinateRegion และตั้งค่าสแปนละติจูดและลองจิจูด ด้านล่างนี้เป็นข้อมูลอ้างอิงโดยย่อและนี่คือข้อมูลอ้างอิงของ iOS จะไม่ทำอะไรแฟนซี แต่ควรให้คุณตั้งค่าการซูมเมื่อวาดแผนที่


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

แก้ไข 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
สิ่งนี้ไม่ได้สร้างความแตกต่างสำหรับฉันเมื่อฉันเปลี่ยนค่าบางอย่างมันก็ไม่โหลดแผนที่
ระบบ

คุณกำลังตั้งค่านี้เมื่อแผนที่โหลดหรือคุณกำลังพยายามจัดการหลังจากโหลดเสร็จแล้ว? คุณใช้ 1 หรือน้อยกว่าเป็นเดลต้าของคุณหรือไม่? เพียงแค่พยายามทำความเข้าใจข้อกำหนด
DerekH

ฉันตั้งค่าก่อนรันไทม์ ฉันทดสอบค่าที่สูงกว่าและต่ำกว่า 1
ระบบ

1
คำตอบที่ดี แต่ลองเปลี่ยนละติจูดลองจิจูดเป็น 0.1 - มันถูกซูมมากขึ้น
Daniel Krzyczkowski

12

การใช้งาน Swift อย่างง่ายหากคุณใช้ร้านค้า

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

จากคำตอบของ @ Carnal


12

การใช้งานอย่างรวดเร็ว

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
ฉันไม่แน่ใจ 100% แต่ผมเดาว่าเมื่อคุณสร้างของคุณIBOutletที่คุณmapคุณสามารถกำหนดเป็นแทนการที่เรียบง่ายMapViewWithZoom MKMapViewจากนั้นคุณสามารถตั้งค่าระดับการซูมด้วยmap.zoomLevel = 1หรือmap.zoomLevel = 0.5
Zonker.in เจนีวา

1
ความคิดเห็นบางส่วนเกี่ยวกับสิ่งนี้จะเป็นประโยชน์มากขึ้นมันทำงานใน Swift 3
nyxee

ทางออกที่ดี! แต่ฉันชอบมันมากกว่าในฐานะส่วนขยายและมีสิ่งที่แปลกอยู่อย่างหนึ่ง: ในการย่อภาพต้องลดลง 2 อย่างmapView.zoomLevel -= 2
Alexander

7

สำหรับSwift 3มันค่อนข้างเร็วไปข้างหน้า:

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

เพียงกำหนด lat-, long-Meters <CLLocationDistance>แล้ว mapView ก็จะปรับระดับการซูมให้พอดีกับค่าของคุณ


คุณหมายถึงอะไรโดย "mapView จะปรับระดับการซูมให้พอดีกับค่าของคุณ" ฉันคิดว่า OP ต้องการตั้งระดับการซูมด้วยตัวเองหรือคุณจะทำอย่างไรกับอินพุตที่คุณแนะนำ
riper

6

บนพื้นฐานที่ดี @ AdilSoomro ของคำตอบ ฉันได้คิดสิ่งนี้:

@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

ฉันหวังว่าการติดตามส่วนของโค้ดจะช่วยคุณได้

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

คุณสามารถเลือกค่าใดก็ได้แทน 0.5 เพื่อลดหรือเพิ่มระดับการซูม ฉันใช้วิธีการเหล่านี้เมื่อคลิกปุ่มสองปุ่ม


2

คำตอบ Swift 2.0 ที่ใช้ NSUserDefaults เพื่อบันทึกและเรียกคืนการซูมและตำแหน่งของแผนที่

ฟังก์ชั่นบันทึกตำแหน่งแผนที่และซูม:

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

เรียกใช้ฟังก์ชันทุกครั้งที่ย้ายแผนที่:

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

ฟังก์ชั่นบันทึกการซูมแผนที่และตำแหน่ง:

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

เพิ่มสิ่งนี้ใน viewDidLoad:

restoreMapRegion()

1

ฉันรู้ว่านี่เป็นการตอบกลับช้า แต่ฉันแค่อยากจะแก้ปัญหาเรื่องการตั้งค่าระดับการซูมด้วยตัวเอง คำตอบของ goldmine ดีมาก แต่ฉันพบว่ามันทำงานได้ไม่ดีพอในแอปพลิเคชันของฉัน

จากการตรวจสอบอย่างใกล้ชิด goldmine ระบุว่า "เส้นลองจิจูดมีระยะห่างเท่า ๆ กันที่จุดใด ๆ ของแผนที่" นี่ไม่เป็นความจริง แต่เป็นเส้นละติจูดที่มีระยะห่างเท่ากันตั้งแต่ -90 (ขั้วใต้) ถึง +90 (ขั้วเหนือ) เส้นลองจิจูดมีระยะห่างที่กว้างที่สุดที่เส้นศูนย์สูตรโดยมาบรรจบกันที่จุดที่เสา

การใช้งานที่ฉันได้นำมาใช้จึงต้องใช้การคำนวณละติจูดดังนี้:

@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

หวังว่ามันจะช่วยในช่วงปลายนี้


ตกลงไม่สนใจข้างต้น Goldmine ถูกต้องเส้นลองจิจูดมีระยะห่างเท่ากันเนื่องจากแน่นอนว่า Mercator projection ใช้สำหรับแผนที่ ปัญหาของฉันเกี่ยวกับวิธีแก้ปัญหาเกิดจากข้อผิดพลาดเล็กน้อยอื่น ๆ ในแอปพลิเคชันของฉันเกี่ยวกับคลาสย่อยของคลาส MKTileOverlay ของ iOS 7 ใหม่
gektron

คุณอาจต้องการพิจารณาอัปเดตโพสต์ของคุณเพื่อแสดงข้อมูลที่คุณรวมไว้ในความคิดเห็นของคุณ
Derek Lee

1

สวิฟท์:

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

locValue คือพิกัดของคุณ


1

นี่ผมใส่คำตอบและการทำงานของฉันสำหรับรวดเร็ว 4.2

MKMapView center และซูมเข้า


ถ้าฉันคลิกที่นี่และเลื่อนลงและคลิกที่ลิงค์ของคุณที่นั่นฉันจะพบตัวเองที่นี่อีกครั้งจากนั้นฉันก็คลิกที่นี่และตอนนี้ฉันติดอยู่ในวงวนที่ไม่มีที่สิ้นสุด😏
Matthijs

@Matthijs ฉันได้แก้ไขลิงค์แล้ว โปรดตรวจสอบและโหวตคำตอบ
Ashu

0

ขึ้นอยู่กับคำตอบของ quentinadam

สวิฟต์ 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))

ขอบคุณดูดีเมื่อแผนที่หันไปทางทิศเหนือ แต่ถ้าคุณหมุนแผนที่ล่ะ? จะเกิดอะไรขึ้นถ้ามุมหยิกแตกต่างจาก 0?
pierre23

0

MKMapViewส่วนขยายตามคำตอบนี้ (+ ความแม่นยำของระดับการซูมจุดลอยตัว):

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)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.