2009-09-05 88 views
15

我节省地图区域为用户默认时,我的iPhone应用程序被关闭这样的:的MKMapView秀正确保存区域

MKCoordinateRegion region = mapView.region; 
[[NSUserDefaults standardUserDefaults] setDouble:region.center.latitude forKey:@"map.location.center.latitude"]; 
[[NSUserDefaults standardUserDefaults] setDouble:region.center.longitude forKey:@"map.location.center.longitude"]; 
[[NSUserDefaults standardUserDefaults] setDouble:region.span.latitudeDelta forKey:@"map.location.span.latitude"]; 
[[NSUserDefaults standardUserDefaults] setDouble:region.span.longitudeDelta forKey:@"map.location.span.longitude"]; 

当应用程序再次启动,Ш读取这些值回以同样的方式,使用户可以看到完全相同的地图视图,因为它是最后一次:

MKCoordinateRegion region; 

region.center.latitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"]; 
region.center.longitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"]; 
region.span.latitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"]; 
region.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"]; 

NSLog([NSString stringWithFormat:@"Region read : %f %f %f %f", region.center.latitude, region.center.longitude, region.span.latitudeDelta, region.span.longitudeDelta]); 

[mapView setRegion:region]; 

NSLog([NSString stringWithFormat:@"Region on map: %f %f %f %f", mapView.region.center.latitude, mapView.region.center.longitude, mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta]); 

我从用户默认值读出的区域是(不奇怪)完全相同的,当它被保存为。请注意,保存的内容直接来自地图,因此不会以任何方式进行转换。我用setRegion:方法将其重新设置在地图上,但是它不同!

示例结果:

Region read : 50.241110 8.891555 0.035683 0.042915<br> 
Region on map: 50.241057 8.891544 0.050499 0.054932 

是否有人知道为什么会这样?

+0

我发现了一个解决方案,可以准确获得您想要的地图区域:请参阅我的帖子http://stackoverflow.com/questions/3612007/mkmapview-setregion-snaps-to-predefined-zoom-levels/7935 – AlexWien 2011-10-29 13:06:54

回答

2

我有同样的问题。这非常令人沮丧。似乎MKMapView的文档在某些数据类型方面是不正确的。

如果将区域参数设置为(double)s,则会出现您遇到的错误。但是,如果区域参数通过(浮动)s,您将获得正确的行为。

所以尽量

MKCoordinateRegion region = {{0.0f,0.0f},{0.0f,0.0f}}; 

region.center.latitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"]; 
region.center.longitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"]; 
region.span.latitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"]; 
region.span.longitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"]; 

mapView.region = region; 
+0

感谢你的答案。 我试图通过这种方式解决我的问题,但仍然没有运气... 我很确定问题是双重浮动截断,但现在不知道如何解决它。 其他人请吗? – 2009-09-08 11:03:55

0

我无法验证这工作。其他人可以这样做吗?我愿意打赌,你所看到的是将你的双打截断成浮游物的效果。在某些情况下,当发生这种情况时,我发现我可以将跨度乘以0.9999并重置该区域,然后它就会成为我想要的。但并非所有地区 - 有时都非常不同,高达20%不同,尤其是小跨度。

+0

呃,对不起 - 这与下面的注释有关:“我有同样的问题,这是非常令人沮丧的......” – Colin 2009-09-07 14:17:28

8

这里的问题是当你设置区域时,地图缩放级别“捕捉”到最近的缩放阈值。 (我怀疑这些缩放阈值是双击或双指轻敲时获得的缩放量)

因此,如果地图显示缩放级别1,并且您将区域设置为相同的跨度值:region = [mapView region]; [mapView setRegion:region];它会“跳跃”到最接近水平1的的最近缩放级别,即级别2,您将缩小大约两倍。

原始海报的解决方法是在设置区域之前略微减小跨度值,以便在视图快照时捕捉到它所在的缩放级别,而不是上面的缩放级别。

例如

region.span.latitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"] * 0.999;

region.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"] * 0.999;

如果用户已经用双水龙头缩放(因此从门槛跳跃阈值),这个工作得很好,把他们送回了同样的观点几乎完全。

但是,如果它们捏缩放,并且视图在缩放阈值之间的一半,它仍然会突出到下一个级别。在这种情况下不太好,但目前还没有解决。

苹果雷达上有一些开放的bug,希望它能在未来的版本中修复。

+0

这不是一个错误。它有很好的文件记录和行为完全符合文件。https://developer.apple.com/library/iOS/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html – Frizlab 2013-04-05 08:25:09

+0

@frizlab链接是死的,它指向什么? – 3366784 2018-01-22 05:13:33

+0

@ 3366784 https://developer.apple.com/documentation/mapkit/mkmapview。无论如何,评论已经过时了,现在“MKMapView”按预期工作。 – Frizlab 2018-01-22 13:01:05

2

好的,所以我一直在努力解决这个问题一段时间,我想我已经想出了一个有效的解决方法,灵感来源于Crufty的理论(MKMapView show incorrectly saved region)。基本上,如果您在地图视图完成其初始加载后完成初始加载(从“弹出”行为完成)后,使用从NSUserDefaults中获取的值设置地图视图区域,则地图区域将成为您期望的地图区域。诀窍是在已初始化的地图视图下游的某处找到应用程序代码中的钩子。不漂亮,但它适用于我。感谢Crufty的洞察力。

0

我发现更大的成功使用倍增因子0.9而不是0.999它仍然有时会推出,但似乎拥抱更接近所需的缩放。仍然愿意解决这个问题只是说我击败它!哈哈

-1

如果设置了InterfaceBuilder下的MapView,确保你不这样做:

_mapView = [[MKMapView alloc] init]; 

只要我删除了这个初始化线,我的地图视图突然开始正确响应所有更新我寄了。我怀疑会发生什么情况是,如果你执行alloc init,它实际上会创建另一个视图,而不会显示在任何地方。你在屏幕上看到的那个是你的笔尖初始化的那个。但是如果你将init分配给一个新的,那么这是其他地方的事情,它不会做任何事情。

0

尝试也储存态度像

self.lastCameraAtitude = self.mapView.camera.altitude; 

和当u配置图

[self.mapView.camera setAltitude:self.lastCameraAtitude]; 

这将为同一区域相同的相机设置。在你的情况下,你只设置区域,而不是相机。

0

这里有一个斯威夫特扩展正确编码和解码MKCoordinateRegion:

extension MKCoordinateRegion { 

    var encode:[String: AnyObject] { 
     return ["center": 
        ["latitude": self.center.latitude, 
        "longitude": self.center.longitude], 
       "span": 
        ["latitudeDelta": self.span.latitudeDelta, 
        "longitudeDelta": self.span.longitudeDelta]] 
    } 

    init?(decode: [String: AnyObject]) { 

     guard let center = decode["center"] as? [String: AnyObject], 
      let latitude = center["latitude"] as? Double, 
      let longitude = center["longitude"] as? Double, 
      let span = decode["span"] as? [String: AnyObject], 
      let latitudeDelta = span["latitudeDelta"] as? Double, 
      let longitudeDelta = span["longitudeDelta"] as? Double 
     else { return nil } 


     self.center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) 
     self.span = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta) 
    } 
} 

这是如何使用它:

// Save 
NSUserDefaults.standardUserDefaults().setObject(mapView.region.encode, forKey: "mapRegion01") 

// Restore 
if let dict = NSUserDefaults.standardUserDefaults().dictionaryForKey("mapRegion01"), 
    let myRegion = MKCoordinateRegion(decode: dict) { 

    // do something with myRegion 
} 
0

最近我打的是同样的事情。从早期的答案使用的见解,下面的迅速落实4工作对我来说:

override func viewWillAppear(_ animated: Bool) { 
    if isMovingToParentViewController { 
     setInitialRegion() 
     DispatchQueue.main.asyncAfter(deadline: .now(), execute: { 
      self.setInitialRegion() 
     }) 
    } 
} 

该规定最初的变焦区域时在地图视图控制器推入视图。同步调用setInitialRegion会将区域设置为缩放级别。对setInitialRegion的异步调用将设置确切的区域。仍然需要同步调用来删除缩放工件。