2009-09-05 20 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的異步調用將設置確切的區域。仍然需要同步調用來刪除縮放工件。