Как узнать, виден ли вид UIViewController
У меня есть приложение панели вкладок, с множеством просмотров. Есть ли способ узнать, является ли конкретный UIViewController
в настоящее время виден изнутри UIViewController
? (ищет недвижимость)
19 ответов
Свойство окна представления не равно nil, если представление в данный момент видно, поэтому проверьте основной вид в контроллере представления:
[EDIT] Вызов метода view приводит к загрузке вида (если он не загружен), что не является необходимым и может быть нежелательным. Лучше сначала проверить, загружен ли он. Я добавил вызов isViewLoaded, чтобы избежать этой проблемы.
if (viewController.isViewLoaded && viewController.view.window) {
// viewController is visible
}
Или, если у вас есть UINavigationController, управляющий контроллерами представления, вы можете вместо этого проверить его свойство visibleViewController.
Также в Swift на iOS 9 (или новее):
if viewController.viewIfLoaded?.window != nil {
// viewController is visible
}
Вот решение @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
Есть несколько проблем с вышеуказанными решениями. Если вы используете, например, 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;
}
Для тех из вас, кто ищет версию Swift 2.2, ответ:
if self.isViewLoaded() && (self.view.window != nil) {
// viewController is visible
}
и Свифт 3:
if self.isViewLoaded && (self.view.window != nil) {
// viewController 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
}
}
}
Вы хотите использовать UITabBarController
"s selectedViewController
имущество. Все контроллеры представления, подключенные к контроллеру панели вкладок, имеют tabBarController
таким образом, вы можете установить свойство из любого кода контроллера представления:
if([[[self tabBarController] selectedViewController] isEqual:self]){
//we're in the active controller
}else{
//we are not
}
Я сделал быстрое расширение, основываясь на ответе @progrmr.
Это позволяет легко проверить, если UIViewController
на экране вот так:
if someViewController.isOnScreen {
// Do stuff here
}
Расширение:
//
// UIViewControllerExtension.swift
//
import UIKit
extension UIViewController{
var isOnScreen: Bool{
return self.isViewLoaded() && view.window != nil
}
}
Для моих целей, в контексте контроллера представления контейнера, я обнаружил, что
- (BOOL)isVisible {
return (self.isViewLoaded && self.view.window && self.parentViewController != nil);
}
работает хорошо.
Я использую это небольшое расширение в Swift 5, что позволяет легко и просто проверить наличие любого объекта, который является членом UIView.
extension UIView {
var isVisible: Bool {
guard let _ = self.window else {
return false
}
return true
}
}
Тогда я просто использую его как простую проверку операторов...
if myView.isVisible {
// do something
}
Я надеюсь, что это помогает!:)
Хорошая точка зрения, что представление появляется, если оно уже находится в стеке иерархии окон. таким образом, мы можем расширить наши классы для этой функции.
extension UIViewController {
var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
}
extension UIView {
var isAppeared: Bool { window != nil }
}
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.
Надеюсь, это кому-нибудь поможет. Спасибо! Приветствия.
Подход, который я использовал для модального представленного контроллера представления, состоял в том, чтобы проверить класс представленного контроллера. Если представленный контроллер представления был ViewController2
тогда я бы выполнил некоторый код.
UIViewController *vc = [self presentedViewController];
if ([vc isKindOfClass:[ViewController2 class]]) {
NSLog(@"this is VC2");
}
Если вы используете 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
}
Я нашел эти функции в 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
появился или нет.
Если вы используете контроллер навигации и просто хотите узнать, используете ли вы активный и самый верхний контроллер, используйте:
if navigationController?.topViewController == self {
// Do something
}
Этот ответ основан на комментарии ma11hew28.
Если у вас есть более сложный сценарий, посмотрите другие ответы выше.
Вы можете проверить это по window
имущество
if(viewController.view.window){
// view visible
}else{
// no visible
}
Мне нужно было это, чтобы проверить, является ли контроллер представления текущим просмотренным контроллером, я сделал это, проверив, есть ли представленный контроллер представления или протолкнул через навигатор, я отправляю это в случае, если кому-то нужно такое решение:
if presentedViewController != nil || navigationController?.topViewController != self {
//Viewcontroller isn't viewed
}else{
// Now your viewcontroller is being viewed
}
Окно:
window.isVisible
viewController.view.window?.isVisible ?? false
Вид (macOS):
extension NSViewController {
var isOnScreen: Bool {
return ( self.isViewLoaded && view.window != nil )
}
}
Поскольку UIAlertController
происходит от UIViewController
Вы можете просто использовать isBeingPresented
if (alertController.isBeingPresented) {
// alert is showing
}