我有一个标签栏应用程序,有许多视图。有没有办法知道一个特定的UIViewController当前在UIViewController中是可见的?(寻找物业)
如果当前视图是可见的,视图的window属性是非空的,所以检查视图控制器中的主视图:
调用view方法会导致视图被加载(如果它没有被加载),这是不必要的,也可能是不希望看到的。最好先检查一下它是否已经加载了。我添加了对isViewLoaded的调用来避免这个问题。
if (viewController.isViewLoaded && viewController.view.window) {
// viewController is visible
}
自从iOS9以来,这变得更容易了:
if viewController.viewIfLoaded?.window != nil {
// viewController is visible
}
或者如果你有一个UINavigationController管理视图控制器,你可以检查它的visibleViewController属性。
你想要使用UITabBarController的selectedViewController属性。所有附加到标签栏控制器的视图控制器都有一个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。
希望这能帮助到一些人。谢谢!欢呼。
对于那些正在寻找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
}
如果你正在使用一个导航控制器,只是想知道你是否在活动和最顶层的控制器,那么使用:
if navigationController?.topViewController == self {
// Do something
}
这个答案是基于@mattdipasquale的评论。
如果您有一个更复杂的场景,请参阅上面的其他答案。
我需要这个来检查是否视图控制器是当前的视图控制器,我通过检查是否有任何呈现的视图控制器或通过导航器推送,我张贴它以防有人需要这样的解决方案:
if presentedViewController != nil || navigationController?.topViewController != self {
//Viewcontroller isn't viewed
}else{
// Now your viewcontroller is being viewed
}
我在Swift 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 }
}
亮点:
window.isVisible
viewController.view.window?.isVisible ?? false
View (macOS):
extension NSViewController {
var isOnScreen: Bool {
return ( self.isViewLoaded && view.window != nil )
}
}
推荐文章
- 更改UITextField和UITextView光标/插入符颜色
- 'Project Name'是通过优化编译的——步进可能会表现得很奇怪;变量可能不可用
- 如何设置回退按钮文本在Swift
- 模拟器慢动作动画现在打开了吗?
- 如何为TableView创建NSIndexPath
- 滑动删除和“更多”按钮(就像iOS 7的邮件应用程序)
- 使UINavigationBar透明
- 如何改变推和弹出动画在一个基于导航的应用程序
- 删除/重置核心数据中的所有条目?
- setNeedsLayout vs. setNeedsUpdateConstraints和layoutIfNeeded vs. updateConstraintsIfNeeded
- 不区分大小写的比较
- 我怎么能得到一个uiimage的高度和宽度?
- 我如何模仿地图应用程序的底部表格?
- 改变导航栏后退按钮的颜色
- iOS应用程序“应用程序无法验证”只在一台设备上