MKMapView显示不正确的保存区域

当我的iPhone应用程序正在closures时,我将地图区域保存为用户默认值:

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 

有人知道为什么会发生这种情况吗?

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

因此,如果地图显示比例缩放级别1,那么您将区域设置为相同的跨度值: region = [mapView region]; [mapView setRegion:region]; region = [mapView region]; [mapView setRegion:region]; 它会“捕捉”到1级以上的最接近的缩放级别,也就是2级,而且会缩小大约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,希望能在未来的版本中修复。

好的,所以我一直在努力解决这个问题一段时间了,我想我已经提出了一个有效的解决scheme,灵感来自Crufty的理论( MKMapView显示错误保存区域 )。 基本上,如果在地图视图完成其初始加载(完成“popup”行为)之后,使用从NSUserDefaults中获取的值设置地图视图区域,那么地图区域将是您所期望的。 诀窍是在已经初始化的地图视图下游的应用程序代码中find一个钩子。 不漂亮,但它对我来说非常合适。 感谢Crufty的洞察力。

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

如果你设置区域参数为(double),你将会得到你所遇到的错误。 但是,如果区域参数被传递(float),你将会得到正确的行为。

所以试试

 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; 

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

我发现使用倍增系数0.9而不是0.999获得更大的成功,但它仍然有时会推出,但似乎拥抱更接近所需的缩放。 仍然喜欢解决这个问题只是说我打败了它! 哈哈

也试试像存储态度

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

当你configuration你的地图

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

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

这里有一个Swift扩展来正确编码和解码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 } 

如果在InterfaceBuilder中设置MapView,请确保不要这样做:

 _mapView = [[MKMapView alloc] init]; 

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