2012-01-23 64 views
3

我有一些UI,我需要重新繪製基於當用戶平移或縮放地圖的MKMapView的更改。監視器MKMapView重繪事件

當前我正在使用移動事件手勢識別器和MKMapViewDelegate regionDidChangeAnimated消息來重繪我的依賴用戶界面。這是我需要的90%。

我錯過的事件是從用戶提起手指(不再有移動事件)到MKMapViewDelegate regionDidChangeAnimated消息被觸發的時候。在此期間,地圖緩慢停止,我的依賴用戶界面停留在不同步的地圖平鋪內容上。

是否有一個較低級別的API,當UIView(在這裏是MKMapView)內容被重繪時會通知我?

更新

我試圖創建一個代理的MKMapView子類,轉發的drawRect調用到我提供的委託。我得到了第一場比賽,但沒有一場比賽,所以這不利於我的困境。

+0

我已經提交了與此相關的Apple Bug(13774496)(不知道地圖何時完成繪製),並創建了一個示例應用程序來顯示iOS6上仍然存在問題:https://github.com/iwasrobbed/MapKitDelegateBug – iwasrobbed

+0

@ iWasRobbed真棒!謝謝:) – RedBlueThing

回答

2

IIRC,MKMapView不幸地爲not KVO-compliant@"region"

你可能會破解你在regionWillChangeAnimated中設置NSTimer,使用它在scroll/pan/etc中刷新你的UI,並在regionDidChangeAnimated中丟棄它。雖然不太優雅,但如果您需要非常快速,它可能不適合您的需求。

或者,您可以在MKMapView的子視圖中查找UIScrollView,並觀察它的transform

(我沒有測試任何這些。)

在任何情況下,我懷疑監測重繪在MKMapView事件將會有什麼用處:MKMapView使用CATiledLayer異步執行其繪圖,這樣你就可以當你完成時,你甚至不能確定


編輯:這顯然不與iOS 6,當然工作,這實在不應該感到驚訝。但是,據我所知,委託方法的行爲相同,所以OP的問題仍然存在。我沒有尋找更新的解決方案。

+0

謝謝你。您關於MKMapView不符合KVO標準的觀點爲我節省了一些時間。在發佈之前,我已經嘗試了計時器選項,並且如您所懷疑的那樣,它並沒有達到要求。你會得到tick,因爲解決方案需要通過UIScrollView的視圖挖掘並在contentOffset屬性上使用KVO。你介意我是否用工作代碼編輯你的答案? – RedBlueThing

+1

不客氣,沒問題:) –

+0

mkmapview似乎沒有在ios6中的uiscrollview子視圖:( – jonydep

-1

MKMapView有許多重繪的子視圖。它很難找到哪個視圖或圖層被繪製...

或者你可以嘗試找到一些MKMapView屬性被改變。您可以使用Key Value Observing(KVO)機制來完成此操作。 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html

例如, (屬性是可以改變的,以任何你需要的)

[myMapView addObserver:self forKeyPath:@"region" options:NSKeyValueObservingOptionNew context:nil]; 
    [myMapView addObserver:self forKeyPath:@"centerCoordinate" options:NSKeyValueObservingOptionNew context:nil]; 

而且你應該實現observeValueForKeyPath:ofObject:change:context:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    // Do something that you want with keyPath; 
} 

每當你的MapView獲得對您定義的每個屬性的新值,這個方法會被解僱。

+0

+1你的方向是正確的一步,所以謝謝:)正如@nico_nico指出的那樣,MKMapView對於這些屬性不是KVO兼容的。另外我注意到你的addObserver調用的params不太正確(mYMapView和self應該交換)。再次感謝。 – RedBlueThing

+1

:)感謝您的回覆。 @nico_nico是正確的。我沒有注意到KVO compliation的MKMapView。 – Alkimake

+0

我編輯代碼 – Alkimake

1

討厭張貼這些解決方案,但是。 MKMapView本身有很多子視圖。 在它的子視圖層次結構中,有一個類MKTiledView的視圖,它具有TiledLayer作爲圖層。

所以,實際上,您不能以「正常」方式解決渲染通知。

平鋪層通過不斷調用-drawLayer:inContext:它的委託的方法呈現它的內容,哪個MKTiledView是。這些調用可以在不同的線程中同時執行。

您沒有從MKMapView接收聲明(更新),因爲它沒有自行更新。只有它的基本內容正在更新。

所以。存在更好的解決方案。 我的解決方案取決於視圖層次結構和方法的調整。 這取決於你,使用它或不。

創建類別的方法中,我們將張貼需要更新「更新通知」,以自定義視圖

@implementation UIView (Custom) 

- (void)drawCustomLayer:(CALayer *)layer inContext:(CGContextRef)ctx { 
    NSLog(@"Need to draw custom layer :%@ in context %@, Thread: %@", layer, ctx, [NSThread currentThread]); 

    // Calling old method 
    [self drawCustomLayer:layer inContext:ctx]; 
} 

@end 

//交換MKTiledView的方法實現我們的自定義實現

#import <objc/runtime.h> 

Class tileViewclass = NSClassFromString(@"MKMapTileView"); 
Class viewClass = NSClassFromString(@"UIView"); 
SEL originalSelector = @selector(drawLayer:inContext:); 
SEL newSelector = @selector(drawCustomLayer:inContext:); 
Method origMethod = class_getInstanceMethod(tileViewclass, originalSelector); 
Method newMethod = class_getInstanceMethod(viewClass, newSelector); 
method_exchangeImplementations(origMethod, newMethod); 

仍在尋找更好的解決方案。

+0

+1謝謝你提供的解決方案。最後它遲了一點,因爲我剛剛嘗試了@ nico_nico的UIScrollView建議,它的工作非常好。 – RedBlueThing