2010-03-16 86 views
19

有沒有辦法得到一個通知,回調或其他方式來調用一個方法,每當一個UIView變得可見的用戶,即當一個UIScrollview是一些UIViews的超級視圖,並且這樣一個UIView的ViewController應該得到當用戶看到它的視圖時通知它?如何在UIView變得可見時得到通知?

我知道的可能,但檢查不那麼優雅的解決了滾動滾動哪個位置(通過UIScrollViewDelegate的方法)和計算,如果子視圖中的任何一個可見...
但我正在尋找以更普遍的方式來做到這一點。

+0

我的應用程序的導航基於水平滾動UIScrollView。我也通過分類的UIWindow攔截觸摸。因此,當前可見視圖的ViewController需要將自己註冊爲委託給子類UIWindow。這就是我希望在視圖變得可見時得到通知的原因。 – 2010-03-17 21:09:52

回答

8

如果您的視圖呈現行爲,它應該位於視圖控制器內。在視圖控制器上,每次出現視圖時都會調用viewDidAppear方法。

- (void)viewDidAppear:(BOOL)animated 
+7

viewDidAppear的問題在於,它僅在使用導航控制器時被調用。在我的情況下,視圖從屏幕上滾動*滾動,然後滾動回來。滾動似乎不觸發viewDidAppear .... – 2010-03-19 11:19:56

+1

那麼,什麼可以表明視圖是否出現在屏幕上與滾動? – 2014-05-21 08:01:12

+0

「它應該在視圖控制器內。」 - 並且視圖控制器僅適用於全屏視圖。有時候我們只能看到屏幕的一部分。 – Jonny 2016-02-09 06:29:28

0

視圖的圖層屬性應該告訴我們,如果這種觀點是可見或不可見

[view.layer visibleRect]; 

但心不是爲我工作。

因此,解決方法是使用UiScrollView contentOffset屬性來計算特定的視圖是否可見。

+1

那麼如何添加一個觸發器,當該值發生變化時觸發? – 2015-08-07 14:55:26

+0

很久以前我就回答了這個問題,即使我忘記了上下文。 子類UIView並使用以下方法。 https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/doc/uid/TP40006816-CH3-SW139 – 2015-08-10 11:31:36

+0

這就是我現在正在做的。我想聽一門外部課程。 – 2015-08-17 19:43:45

1

我不認爲有一種通用的方式來做到這一點的意見。聽起來像你被困在scrollViewDidEndScrolling和其他ScrollViewDelegate方法。但我不確定爲什麼你說它很優雅,它們很簡單。

8

我已經設法解決這個問題是這樣的:

首先,添加一個類別的UIView以下方法:

// retrieve an array containing all super views 

-(NSArray *)getAllSuperviews 
{ 
    NSMutableArray *superviews = [[NSMutableArray alloc] init]; 

    if(self.superview == nil) return nil; 

    [superviews addObject:self.superview]; 
    [superviews addObjectsFromArray:[self.superview getAllSuperviews]]; 

    return superviews; 
} 

然後,在你看來,檢查窗口屬性設置:

-(void)didMoveToWindow 
{ 
    if(self.window != nil) 
     [self observeSuperviewsOnOffsetChange]; 
    else 
     [self removeAsSuperviewObserver]; 
} 

如果它被設置,我們會觀察每個上海華盈的「contentOffset」上的任何變化。如果窗口是零,我們將停止觀察。您可以將的keyPath更改爲任何其他財產,也許「幀」如果在你的superviews沒有的UIScrollView:

-(void)observeSuperviewsOnOffsetChange 
{ 
    NSArray *superviews = [self getAllSuperviews]; 
    for (UIView *superview in superviews) 
    { 
     if([superview respondsToSelector:@selector(contentOffset)]) 
      [superview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil]; 
    } 
} 

-(void)removeAsSuperviewObserver 
{ 
    NSArray *superviews = [self getAllSuperviews]; 
    for (UIView *superview in superviews) 
    { 
     @try 
     { 
      [superview removeObserver:self forKeyPath:@"contentOffset"]; 
     } 
     @catch(id exception) { } 
    } 
} 

現在實行「observeValueForKeyPath」 - 方法:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if([keyPath isEqualToString:@"contentOffset"]) 
    { 
     [self checkIfFrameIsVisible]; 
    } 
} 

最後,檢查是否視圖的框架在窗口框架內可見:

-(void)checkIfFrameIsVisible 
{ 
    CGRect myFrameToWindow = [self.window convertRect:self.frame fromView:self]; 
    if(myFrameToWindow.size.width == 0 || myFrameToWindow.size.height == 0) return; 
    if(CGRectContainsRect(self.window.frame, myFrameToWindow)) 
    { 
     // We are visible, do stuff now 
    } 
} 
+0

感謝您的詳細解決方案。我嘗試了一下,但問題是在我有機會移除觀察者之前,超級視圖正在被釋放。我甚至觀察他們的「超級觀點」關鍵路徑的變化,但它沒有幫助。這絕對是KVO最糟糕的部分。 – phatmann 2015-08-27 18:13:58

+0

這應該是沒有問題的,我猜。如果superview被釋放,觀察視圖(我們想知道它的視圖是否可見)也應該被釋放,因爲它是子視圖。 – Thomas 2015-08-27 22:20:52

+0

你說得對。我的問題是我沒有在所有關鍵路徑上調用removeObserver。也就是說,KVO最佳實踐是保留所有觀察對象的所有權。在這種情況下,這意味着將由'observeSuperviewsOnOffsetChange'創建的超級視圖列表放入成員變量中,並在'removeAsSuperviewObserver'中使用此保留的超級列表列表。這也有輕微的性能優勢。 – phatmann 2015-08-28 19:16:33

相關問題