设置MKMapView的缩放级别


118

我有一张可以正确显示的地图,我现在唯一要做的就是在加载时设置缩放级别。有没有办法做到这一点?

谢谢

Answers:


198

我找到了一个解决方案,它很简单并且可以解决问题。用于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
这应该是选定的答案。我尝试了许多其他建议的解决方案,但都无法正常工作。此代码简单有效。
罗伯茨

1
好答案。但是,缩放会因屏幕尺寸而异,不是吗?
Vinzius 2015年

1
有趣的MKCoordinateRegionMakeWithDistance是,仍然在Swift中。此解决方案有效!
LinusGeffarth'2

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

谢谢!是的,您是对的,实际上我是从项目中取出代码的,这里的代码是函数而不是MKMapView的补充。我刚刚编辑代码以反映您的更正。
quentinadam

1
要计算出当前的缩放级别,该公式的反方向是什么?
尼克,

1
我认为是这样的:double z = log2(360 * ((self.mapView.frame.size.width/256) / self.mapView.region.span.longitudeDelta));
Nick

1
@devios,缩放级别为1,整个世界(360度)适合1个256像素宽的图块。在缩放级别2时,整个世界(360度)适合2个256像素(512像素)的图块。在缩放级别3,整个世界(360°)的4个图像块的256PX(1,024像素x)配合,等等
quentinadam

31

它不是内置的,但我已经看过/使用过代码。这使您可以使用此功能:

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

注意:这不是我的代码,我没有编写代码,因此无法为此赞誉


1
哇,它有很多代码,你会认为它应该是内置的。谢谢。看看效果如何。
系统2010年

1
您可以获取.m和.h文件,将其添加到您的项目中,然后在地图视图控制器中进行引用,并像在MKMapView上将其用作方法一样使用它,这很高兴!
PostMan 2010年

2
没有为我工作,它只显示与以前相同的缩放级别。我一定做错了什么。
系统2010年

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
这对我没有影响,当我更改一些值时,它只是不会加载地图。
系统2010年

是在地图加载时设置此设置,还是在加载后尝试进行操作?您是否使用1或更小的数字作为增量?只是想了解需求。
DerekH 2010年

我在运行时设置它。我测试的上方和下方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而不是simple MKMapView。然后,您可以使用map.zoomLevel = 1map.zoomLevel = 0.5
Zonker.in.Geneva

1
在此方面的意见将更有帮助它在斯威夫特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)
}

只需定义纬度,长米<CLLocationDistance>,mapView将适合您的值的缩放级别。


“ mapView将使缩放级别适合您的值”是什么意思?我假设OP想要自己设置缩放级别,或者在您建议输入的情况下您将如何设置缩放级别?
成熟

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

利用NSUserDefaults的Swift 2.0答案来保存和恢复地图的缩放和位置。

保存地图位置和缩放的功能:

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的答案很好,但是我发现它在我的应用程序中不能很好地工作。

在仔细检查中,金矿指出“经线在地图的任何点均等间隔”。这是不正确的,实际上是纬线在-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

希望它能在后期提供帮助。


好吧,忽略上面的内容。金矿是正确的,因为将墨卡托投影用于地图,所以经度线的间距是相等的。我的解决方案问题来自于我的应用程序中的另一个小错误,该错误与将新的iOS 7 MKTileOverlay类子类化有关。
gektron

您可能需要考虑更新您的帖子,以反映您的评论中包含的信息。
Derek Lee

1

迅速:

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

locValue是您的坐标。


1

在这里,我把我的答案和它的工作迅速4.2

MKMapView中心并放大


如果我单击此处并向下滚动,然后单击此处的链接,我将再次在这里找到自己,然后单击此处,现在我陷入了无限循环。–
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)
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.