Як визначити, чи видно вид UIViewController


569

У мене є додаток на панелі вкладок з багатьма переглядами. Чи є спосіб дізнатись, чи певна UIViewControllerзараз видно зсередини UIViewController? (шукаю нерухомість)


Відповіді:


1097

Властивість вікна перегляду є нульовою, якщо подання переглядається в даний час, тому перевірте головний вигляд у контролері подання:

Викликання методу перегляду призводить до завантаження подання (якщо воно не завантажене), що є непотрібним і може бути небажаним. Було б краще перевірити спочатку, щоб перевірити, чи він уже завантажений. Я додав дзвінок до isViewLoaded, щоб уникнути цієї проблеми.

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

З iOS9 стало простіше:

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

Або якщо у вас є UINavigationController, що управляє контролерами перегляду, ви можете перевірити його властивість видимого ViewViewController .


11
Одна з проблем, пов’язаних із властивістю vidViewControllee UINavigationController, - це випадок, коли ваш vidViewController представляє контролер модального перегляду. У такому випадку модальний вигляд стає видимимViewController, що може бути небажаним. Як би ти впорався з цим?
Моше

12
Це, мабуть, очевидно для всіх, але для мене код мав бути self.isViewLoaded && self.view.window
JeffB6688

85
Будьте уважні в узагальненні цього рішення в інших ситуаціях. Наприклад, якщо ви використовуєте UIPageViewController, представлення для UIViewControllers, які не є поточною сторінкою, все ще може мати властивість вікна без нуля, оскільки вони відображаються поза екраном. У цьому випадку я мав успіх у створенні власного властивості 'isCurrentlyVisible', яке встановлюється у viewDidAppear та viewDidDisappear.
evanflash

4
@Moshe в такому випадку використовуйте topViewController.
ma11hew28

3
Зауважте, що ця відповідь нічого не говорить про реальну видимість. Наприклад, якщо додаток перебуває у фоновому режимі вище, якщо твердження IF скаже «ТАК», тоді як перегляд насправді не видно.
Marek J.

89

Ось рішення @ 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

47

З вищезазначеними рішеннями існує пара питань. Якщо ви використовуєте, наприклад, a UISplitViewController, головний вигляд завжди поверне справжнє значення для

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

1
Це все ще вірно в xCode 7.1.1? Майстер у моєму UISplitViewController повертає НІ для вікна viewController.view.w. Я можу робити щось не так, але я впевнений, що це так.
SAHM

44

Для тих, хто шукає версію відповіді 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 завжди з'явився нуль
Lance Samaria

29

Для модальної презентації на повний екран або над контекстом "видно" може означати, що вона знаходиться на вершині стека контролера перегляду або просто видна, але покрита іншим контролером перегляду.

Щоб перевірити, чи регулятор виду "є контролером перегляду вгорі", чи відрізняється від "видно", слід перевірити стек контролера перегляду навігаційного контролера перегляду.

Я написав фрагмент коду, щоб вирішити цю проблему:

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

Гарний пост! FYI isViewLoadedє власністю з Swift 3.0.
Ючен Чжун

28

Ви хочете використовувати UITabBarController«S selectedViewControllerвласності. Усі контролери перегляду, приєднані до контролера панелі вкладок, мають tabBarControllerнабір властивостей, тому ви можете з будь-якого коду контролерів перегляду:

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

2
Це не працює, якщо контролер перегляду міститься у навігаційному контролері і цей контролер додається до контролера панелі вкладок. Виклик вибраномуViewController поверне контролер навігації, а не поточний контролер перегляду.
Антон Гольмберг

2
@AntonHolmberg у такому випадку знайдіть контролер видимого перегляду таким чином:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
ma11hew28

Або навіть використовувати властивість 'self.tabBarController.selectedIndex', якщо ми зайшли до цього часу.
Володимир Шутюк

12

Я зробив швидке розширення на основі відповіді @ progrmr.

Це дозволяє легко перевірити, чи UIViewControllerє на екрані так:

if someViewController.isOnScreen {
    // Do stuff here
}

Розширення:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

7

Для моїх цілей у контексті контролера перегляду контейнерів я це виявив

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

працює добре.


3

якщо ви використовуєте 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
}

2
Я знайшов цей спосіб більш надійним, ніж прийнята відповідь, коли доступний контролер навігації. Це можна скоротити до: if ([[self.navigationController.visibleViewController isKindOfClass: [self class]]) {
Даррен

3

Підхід, який я використовував для модального представленого контролера перегляду, полягав у тому, щоб перевірити клас представленого контролера. Якби представлений контролер перегляду був, ViewController2я би виконав якийсь код.

UIViewController *vc = [self presentedViewController];

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

3

Я знайшов ці функції в 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, з'явилося чи ні.


3

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.

Сподіваюся, що це комусь допоможе. Дякую! Ура.


3

Якщо ви користуєтесь контролером навігації і просто хочете дізнатися, чи є ви в активному та найвищому контролері, тоді використовуйте:

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

Ця відповідь заснована на @mattdipasquale коментарі .

Якщо у вас складніший сценарій, дивіться інші відповіді вище.


це ніколи не буде називатися, якщо програма перейде у фоновому режимі, а потім на перший план. Я шукаю рішення, де можу перевірити, чи контролер перегляду видно користувачеві чи ні. Користувач може створити програму протягом декількох днів, і коли вона повернеться на перший план, я хотів би оновити інтерфейс користувача. Будь ласка, дайте мені знати, чи можете ви допомогти.
bibscy


0

Мені це потрібно було, щоб перевірити, чи є контролер перегляду поточним контролером, я це робив, перевіряючи, чи є представлений контролер подання чи просувається через навігатор, я публікую його у випадку, якщо комусь потрібно таке рішення:

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

0

Я використовую це невелике розширення в Swift 5 , що дозволяє легко і легко перевіряти наявність будь-якого об'єкта, що є членом UIView .

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

Тоді я просто використовую це як просту перевірку заяви ...

if myView.isVisible {
    // do something
}

Я сподіваюся, що це допомагає! :)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.