如何告诉如果uiviewcontroller的视图是可见的

我有一个标签栏应用程序,有许多视图。是否有一种方法可以知道特定的UIViewController当前从UIViewController中可见?(寻找物业)

288014 次浏览

如果当前视图是可见的,视图的窗口属性是非空的,所以检查视图控制器中的主视图:

调用视图方法会导致视图加载(如果它没有加载),这是不必要的,可能是不希望的。最好先检查一下它是否已经加载了。我添加了对isViewLoaded的调用来避免这个问题。

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

自从iOS9以来,这变得更容易了:

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

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

您希望使用UITabBarControllerselectedViewController属性。所有附加到标签栏控制器的视图控制器都有一个tabBarController属性集,所以你可以在任何视图控制器的代码中:

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

下面是@ program的解决方案,作为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

你可以通过window属性检查它

if(viewController.view.window){


// view visible


}else{


// no visible


}

如果你正在使用一个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
}

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

UIViewController *vc = [self presentedViewController];


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

上述解决方案存在几个问题。如果您正在使用,例如,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;
}

就我的目的而言,在容器视图控制器的上下文中,我已经找到了

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

工作得很好。

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

要检查视图控制器“is the top view controller”和“is visible”是否有很大不同,你应该检查视图控制器的导航控制器的视图控制器堆栈。

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

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

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

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

if someViewController.isOnScreen {
// Do stuff here
}

扩展:

//
//  UIViewControllerExtension.swift
//


import UIKit


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

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

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。

希望这能帮助到一些人。谢谢!欢呼。

对于那些正在寻找斯威夫特2.2版本的答案的人:

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

和# EYZ0:

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

如果你正在使用一个导航控制器,只是想知道你是否在活跃的最高的控制器中,那么使用:

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

这个答案是基于@mattdipasquale的评论。

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

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

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

我在斯威夫特5中使用了这个小扩展,它使它保持简单和容易检查任何对象是UIView的成员。

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

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

if myView.isVisible {
// do something
}

我希望这能有所帮助!:)

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

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


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