ChatGPT解决这个技术问题 Extra ChatGPT

如何判断 UIViewController 的视图是否可见

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


m
mfaani

如果视图当前可见,则视图的 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。
m
ma11hew28

这是@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

v
vincentjames501

上述解决方案存在几个问题。例如,如果您使用 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。我可能做错了什么,但我很确定情况就是这样。
A
Alex Stanciu

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

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

和斯威夫特 3:

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

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

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

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

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

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 以来的属性。
e
executor21

您想使用 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”属性。
B
Besi

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

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

if someViewController.isOnScreen {
    // Do stuff here
}

扩展:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

C
Chris Prince

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

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

效果很好。


B
Bhavin Bhadani

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。

希望这可以帮助某人。谢谢!干杯。


v
valbu17

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

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

然后,我只是将它用作一个简单的 if 语句检查......

if myView.isVisible {
    // do something
}

我希望它有帮助! :)


d
dimpiax

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

extension UIViewController {
  var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
}

extension UIView {
  var isAppeared: Bool { window != nil }
}

M
MrTristan

如果您正在使用 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]]) {
w
wigging

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

UIViewController *vc = [self presentedViewController];

if ([vc isKindOfClass:[ViewController2 class]]) {
    NSLog(@"this is VC2");
}

A
AechoLiu

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


C
Community

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

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

此答案基于 @mattdipasquale 的评论。

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


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

您可以通过 window 属性检查它

if(viewController.view.window){

// view visible

}else{

// no visible

}

A
Abdoelrhman

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

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