2010-05-05 97 views
453

我有一個帶有許多視圖的tabbar應用程序。有沒有辦法從UIViewController中知道某個特定的UIViewController是否可見? (尋找一個性質)如何判斷UIViewController的視圖是否可見

+0

相關:獲得最頂端的UIViewController(HTTP://計算器。com/questions/4067692/getting-the-top-most-uiviewcontroller) – Senseful 2013-07-08 18:12:12

回答

883

視圖的window property是,如果一個視圖是當前可見非零,所以檢查在視圖控制器的主視圖:

[編輯]調用view方法使加載視圖(如果未加載),這是不必要的,並且可能是不希望的。首先檢查是否已經加載會更好。我已將該調用添加到isViewLoaded以避免此問題。

if (viewController.isViewLoaded && viewController.view.window) { 
    // viewController is visible 
} 

或者,如果你有一個UINavigationController管理視圖控制器,你可以改爲檢查其visibleViewController屬性。

而且,斯威夫特在iOS 9(或更高版本):

if viewController.viewIfLoaded?.window != nil { 
    // viewController is visible 
} 
+9

UINavigationController的visibleViewControllee屬性的一個問題就是您的visibleViewController呈現模態視圖控制器的情況。在這種情況下,模式視圖變成了visibleViewController,這可能是不可取的。你將如何處理? – Moshe 2011-06-30 04:31:34

+12

這可能很明顯,但對我來說,代碼必須是self.isViewLoaded && self.view.window – JeffB6688 2013-05-07 14:36:25

+0

請注意,在iOS 7中,導航控制器不會立即將推送的視圖控制器加載到內存中。這與iOS 6不同,您可以推送視圖控制器並立即看到navController.topViewController.isViewLoaded爲true。 – InkGolem 2013-07-22 23:08:06

25

你想使用UITabBarControllerselectedViewController財產。連接到標籤欄控制器的所有視圖控制器有一個tabBarController屬性設置,這樣你就可以從內的任何視圖控制器的代碼:

if([[[self tabBarController] selectedViewController] isEqual:self]){ 
    //we're in the active controller 
}else{ 
    //we are not 
} 
+2

如果視圖控制器包含在導航控制器中並且該控制器添加到標籤欄控制器,則這不起作用。調用selectedViewController將返回導航控制器而不是當前的視圖控制器。 – 2012-12-08 15:12:47

+2

@AntonHolmberg在這種情況下,得到可見的視圖控制器是這樣的:'(((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController' – ma11hew28 2014-01-24 21:06:48

+0

甚至使用'self.tabBarController.selectedIndex'屬性,如果我們走了這麼遠。 – 2016-01-16 18:20:20

82

這裏有@作爲UIViewController類別progrmr的解決方案:

// UIViewController+Additions.h 

@interface UIViewController (Additions) 

- (BOOL)isVisible; 

@end 


// UIViewController+Additions.m 

#import "UIViewController+Additions.h" 

@implementation UIViewController (Additions) 

- (BOOL)isVisible { 
    return [self isViewLoaded] && self.view.window; 
} 

@end 
2

您可以通過window財產

if(viewController.view.window){ 

// view visible 

}else{ 

// no visible 

} 
3

檢查它,如果你使用一個UINavigationController,也想處理模式的看法,以下是我用:

#import <objc/runtime.h> 

UIViewController* topMostController = self.navigationController.visibleViewController; 
if([[NSString stringWithFormat:@"%s", class_getName([topMostController class])] isEqualToString:@"NAME_OF_CONTROLLER_YOURE_CHECKING_IN"]) { 
    //is topmost visible view controller 
} 
+2

當導航控制器可用時,我發現這種方式比接受的答案更可靠。這可以縮短爲:if([self.navigationController.visibleViewController isKindOfClass:[self class]]){ – Darren 2014-10-23 19:31:39

2

,我用一個模式呈現視圖控制器是檢查類所提出的控制器的方法。如果呈現的視圖控制器是ViewController2那麼我會執行一些代碼。

39

上述解決方案有幾個問題。如果您正在使用,例如UISplitViewController,主視圖將始終

if(viewController.isViewLoaded && viewController.view.window) { 
    //Always true for master view in split view controller 
} 

返回true相反,採取這種簡單的方法,這似乎在大多數很好地工作,如果不是所有情況:

- (void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 

    //We are now invisible 
    self.visible = false; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 

    //We are now visible 
    self.visible = true; 
} 
+1

在xCode 7.1.1中這仍然是真的嗎?我的UISplitViewController中的主人爲viewController.view.window返回NO。我可能做錯了什麼,但我確信這是事實。 – SAHM 2016-01-25 05:02:09

7

對於我而言,在容器視圖控制器的情況下,我發現

- (BOOL)isVisible { 
    return (self.isViewLoaded && self.view.window && self.parentViewController != nil); 
} 

效果很好。

17

對於超全屏或超上下文呈現,「可見」可能意味着它位於視圖控制器堆棧之上或者僅可見,但被另一個視圖控制器覆蓋。

若要檢查視圖控制器「是否是頂視圖控制器」與「可見」完全不同,則應檢查視圖控制器的導航控制器的視圖控制器堆棧。

我寫了一段代碼來解決這個問題:

extension UIViewController { 
    public var isVisible: Bool { 
     if isViewLoaded() { 
      return view.window != nil 
     } 
     return false 
    } 

    public var isTopViewController: Bool { 
     if self.navigationController != nil { 
      return self.navigationController?.visibleViewController === self 
     } else if self.tabBarController != nil { 
      return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil 
     } else { 
      return self.presentedViewController == nil && self.isVisible 
     } 
    } 
} 
+0

好帖子! FYI'isViewLoaded'是自Swift 3.0以來的一個屬性。 – 2017-04-19 15:18:37

11

我做了基於@ progrmr的回答迅速擴展。

它可以讓您輕鬆地檢查是否有UIViewController在屏幕上,像這樣:

if someViewController.isOnScreen { 
    // Do stuff here 
} 

擴展:

// 
// UIViewControllerExtension.swift 
// 

import UIKit 

extension UIViewController{ 
    var isOnScreen: Bool{ 
     return self.isViewLoaded() && view.window != nil 
    } 
} 
1

我發現那些功能UIViewController.h

/* 
    These four methods can be used in a view controller's appearance callbacks to determine if it is being 
    presented, dismissed, or added or removed as a child view controller. For example, a view controller can 
    check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear: 
    method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]). 
*/ 

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0); 
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0); 

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0); 
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0); 

也許上述功能可以檢測到ViewController是否出現。

3

的XCode 6.4,爲iOS 8.4,ARC啓用

顯然,大量的做這件事的方式。已經爲我工作的一個下面...

@property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow 

這可以通過以下方式的任何視圖控制器一起使用,

[self.view.window isKeyWindow] 

如果你得到0調用這個屬性在-(void)viewDidLoad ,那麼如果你在-(void)viewDidAppear:(BOOL)animated後打電話給你,你會得到1.

希望這可以幫助別人。謝謝!乾杯。

33

對於那些尋找一個雨燕2.2版本的答案:

if self.isViewLoaded() && (self.view.window != nil) { 
    // viewController is visible 
} 

斯威夫特3

if self.isViewLoaded && (self.view.window != nil) { 
     // viewController is visible 
} 
2

如果您使用的是導航控制器,只是想要知道你是否在有效最上面控制器,則使用:

if navigationController?.topViewController == self { 
    // Do something 
} 

此答案是根據@mattdipasquale的評論。

如果您有更復雜的情況,請參閱上面的其他答案。

-2

由於UIAlertControllerUIViewController衍生您可以只使用isBeingPresented

if (alertController.isBeingPresented) { 
    // alert is showing 
}