【问题标题】:How to tell if UIViewController's view is visible如何判断 ViewController 视图是否可见
【发布时间】:2011-02-16 04:09:02
【问题描述】:

我有一个标签栏应用程序,有很多视图。有没有办法知道特定的UIViewController 当前是否在UIViewController 中可见? (寻找房产)

【问题讨论】:

标签: ios uiview uiviewcontroller uiwindow


【解决方案1】:

如果视图当前可见,则视图的window property 非零,因此请检查视图控制器中的主视图:

调用view 方法会导致视图加载(如果未加载),这是不必要的并且可能是不可取的。最好先检查它是否已经加载。我已经添加了对 isViewLoaded 的调用以避免这个问题。

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

从 iOS9 开始变得更容易了:

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

或者如果你有一个 UINavigationController 管理视图控制器,你可以检查它的visibleViewController 属性。

【讨论】:

  • UINavigationController 的 visibleViewControllee 属性的一个问题是您的 visibleViewController 呈现模态视图控制器的情况。在这种情况下,模态视图变成了 visibleViewController,这可能是不可取的。你会怎么处理呢?
  • 这对每个人来说可能都很明显,但对我来说代码必须是 self.isViewLoaded && self.view.window
  • 在将此解决方案推广到其他情况时要小心。例如,如果您使用 UIPageViewController,则不是当前页面的 UIViewController 的视图可能仍具有非零窗口属性,因为它们正在屏幕外呈现。在这种情况下,我已经成功创建了自己的“isCurrentlyVisible”属性,该属性在 viewDidAppear 和 viewDidDisappear 中设置。
  • @Moshe 在这种情况下,使用topViewController
  • 请注意,这个答案并没有说明真正的可见性。例如,如果应用程序在后台,上面的 IF 语句会在视图不可见时说 YES。
【解决方案2】:

这是@progrmr 的解决方案,作为UIViewController 类别:

// 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

【讨论】:

    【解决方案3】:

    上述解决方案存在几个问题。例如,如果您使用的是UISplitViewController,则主视图将始终为

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

    取而代之的是,采用这种似乎在大多数情况下(如果不是所有情况下)都有效的简单方法:

    - (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;
    }
    

    【讨论】:

    • 在 xCode 7.1.1 中仍然如此吗?我的 UISplitViewController 中的 master 正在为 viewController.view.window 返回 NO。我可能做错了什么,但我很确定情况就是这样。
    【解决方案4】:

    对于那些正在寻找 Swift 2.2 版本答案的人:

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

    Swift 3

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

    【讨论】:

    • 不知道为什么,但我发现执行 self.view.window != nil 会导致它永远无法工作,即使 self.isViewLoaded 为真。删除后,它工作正常。
    • 这只在 viewDidAppear 中对我有用。当我将此添加到 viewWillAppear self.view.window != nil 时总是出现 nil
    【解决方案5】:

    对于超全屏或超上下文模式演示,“可见”可能意味着它位于视图控制器堆栈的顶部,或者只是可见但被另一个视图控制器覆盖。

    要检查视图控制器“是顶部视图控制器”是否与“可见”完全不同,您应该检查视图控制器的导航控制器的视图控制器堆栈。

    我写了一段代码来解决这个问题:

    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
            }
        }
    }
    

    【讨论】:

    • 好帖子!仅供参考 isViewLoaded 是自 Swift 3.0 以来的属性。
    【解决方案6】:

    您想使用UITabBarControllerselectedViewController 属性。附加到选项卡栏控制器的所有视图控制器都有一个 tabBarController 属性集,因此您可以从任何视图控制器的代码中:

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

    【讨论】:

    • 如果视图控制器包含在导航控制器中并且该控制器已添加到选项卡栏控制器,则此方法不起作用。对 selectedViewController 的调用将返回导航控制器,而不是当前视图控制器。
    • @AntonHolmberg 在这种情况下,获取可见视图控制器,如下所示:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
    • 如果我们已经走到这一步,甚至可以使用 'self.tabBarController.selectedIndex' 属性。
    【解决方案7】:

    我根据@progrmr 的回答做了一个快速扩展。

    它可以让您轻松检查UIViewController 是否在屏幕上,如下所示:

    if someViewController.isOnScreen {
        // Do stuff here
    }
    

    扩展名:

    //
    //  UIViewControllerExtension.swift
    //
    
    import UIKit
    
    extension UIViewController{
        var isOnScreen: Bool{
            return self.isViewLoaded() && view.window != nil
        }
    }
    

    【讨论】:

      【解决方案8】:

      出于我的目的,在容器视图控制器的上下文中,我发现

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

      效果很好。

      【讨论】:

        【解决方案9】:

        XCode 6.4,适用于 iOS 8.4,启用 ARC

        显然有很多方法可以做到这一点。对我有用的是以下...

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

        这可以通过以下方式在任何视图控制器中使用,

        [self.view.window isKeyWindow]
        

        如果你在-(void)viewDidLoad 中调用这个属性,你得到0,那么如果你在-(void)viewDidAppear:(BOOL)animated 之后调用这个属性,你得到1。

        希望这对某人有所帮助。谢谢!干杯。

        【讨论】:

          【解决方案10】:

          我在 Swift 5 中使用了这个小扩展,它使检查任何属于 UIView 成员的对象变得简单易行。

          extension UIView {
              var isVisible: Bool {
                  guard let _ = self.window else {
                      return false
                  }
                  return true
              }
          }
          

          那么,我只是把它当作一个简单的 if 语句检查...

          if myView.isVisible {
              // do something
          }
          

          希望对你有帮助! :)

          【讨论】:

            【解决方案11】:

            如果您正在使用 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
            }
            

            【讨论】:

            • 当导航控制器可用时,我发现这种方式比接受的答案更可靠。这可以缩短为:if ([self.navigationController.visibleViewController isKindOfClass:[self class]]) {
            【解决方案12】:

            我用于模态呈现视图控制器的方法是检查呈现控制器的类。如果呈现的视图控制器是ViewController2,那么我将执行一些代码。

            UIViewController *vc = [self presentedViewController];
            
            if ([vc isKindOfClass:[ViewController2 class]]) {
                NSLog(@"this is VC2");
            }
            

            【讨论】:

              【解决方案13】:

              我在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是否出现。

              【讨论】:

                【解决方案14】:

                如果您使用的是导航控制器,并且只想知道您是否在 activetopmost 控制器中,请使用:

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

                此答案基于@mattdipasquale 的评论。

                如果您有更复杂的场景,请参阅上面的其他答案。

                【讨论】:

                • 如果应用程序进入后台然后进入前台,则永远不会调用此方法。我正在寻找一种解决方案,我可以检查视图控制器是否对用户可见。用户可以将应用程序后台运行几天,当它返回前台时,我想更新 UI。如果您能提供帮助,请告诉我。
                【解决方案15】:

                如果视图已经在窗口层次结构堆栈中,那么它就会出现。 因此我们可以为这个功能扩展我们的类。

                extension UIViewController {
                  var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
                }
                
                extension UIView {
                  var isAppeared: Bool { window != nil }
                }
                

                【讨论】:

                  【解决方案16】:

                  你可以通过window属性查看

                  if(viewController.view.window){
                  
                  // view visible
                  
                  }else{
                  
                  // no visible
                  
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    我需要这个来检查视图控制器是否是当前查看的控制器,我通过检查是否有任何呈现的视图控制器或通过导航器推送来做到这一点,我发布它以防有人需要这样的解决方案:

                    if presentedViewController != nil || navigationController?.topViewController != self {
                          //Viewcontroller isn't viewed
                    }else{
                         // Now your viewcontroller is being viewed 
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2016-07-29
                      • 2014-05-03
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-12-29
                      • 2010-10-18
                      • 1970-01-01
                      • 2010-09-12
                      相关资源
                      最近更新 更多