Come sapere se la vista di UIViewController è visibile


Risposte:


1098

La proprietà della finestra della vista è nulla se una vista è attualmente visibile, quindi controlla la vista principale nel controller della vista:

Il richiamo del metodo view provoca il caricamento della view (se non viene caricata) che non è necessario e potrebbe essere indesiderabile. Sarebbe meglio controllare prima di vedere se è già caricato. Ho aggiunto la chiamata a isViewLoaded per evitare questo problema.

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

Da iOS9 è diventato più facile:

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

Oppure, se hai un UINavigationController che gestisce i controller di visualizzazione, puoi invece controllare la sua proprietà visibleViewController .


11
L'unico problema con la proprietà visibleViewControler di UINavigationController è il caso in cui visibleViewController presenta un controller di visualizzazione modale. In tal caso, la vista modale diventa visibleViewController, che potrebbe essere indesiderabile. Come lo gestiresti?
Moshe,

12
Questo è probabilmente ovvio per tutti, ma per me il codice doveva essere self.isViewLoaded && self.view.window
JeffB6688

86
Fai attenzione a generalizzare questa soluzione ad altre situazioni. Ad esempio, se si utilizza un UIPageViewController, le viste per UIViewController che non sono la pagina corrente potrebbero avere ancora una proprietà della finestra non nulla perché vengono visualizzate fuori dallo schermo. In questo caso, ho avuto successo nel creare la mia proprietà 'isCurrentlyVisible' che viene impostata in viewDidAppear e viewDidDisappear.
evanflash,

4
@Moshe in tal caso, utilizzare topViewController.
ma11hew28,

3
Si noti che questa risposta non dice nulla sulla reale visibilità. Ad esempio, se l'app si trova in background sopra l'istruzione IF ti dirà SÌ mentre la vista non è realmente visibile.
Marek J.,

89

Ecco la soluzione di @ progrmr come UIViewControllercategoria:

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

Ci sono un paio di problemi con le soluzioni sopra. Se si utilizza, ad esempio, a UISplitViewController, la vista principale tornerà sempre vera per

if(viewController.isViewLoaded && viewController.view.window) {
    //Always true for master view in split view controller
}

Prendi invece questo semplice approccio che sembra funzionare bene nella maggior parte, se non in tutti i casi:

- (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
È ancora vero in xCode 7.1.1? Il master nel mio UISplitViewController sta restituendo NO per viewController.view.window. Potrei fare qualcosa di sbagliato, ma sono abbastanza sicuro che sia così.
SAHM,

44

Per quelli di voi che cercano una versione Swift 2.2 della risposta:

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

e Swift 3 :

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

Non so perché, ma ho scoperto che fare self.view.window! = Nil non lo fa mai funzionare anche quando self.isViewLoaded è vero. Una volta rimosso, funziona benissimo.
Micah Montoya,

questo ha funzionato solo per me in viewDidAppear. Quando l'ho aggiunto a viewWillAppear self.view.window! = Zero è sempre arrivato zero
Lance Samaria il

29

Per una presentazione modale a schermo intero o contestuale, "è visibile" potrebbe significare che si trova in cima allo stack del controller di visualizzazione o è appena visibile ma è coperto da un altro controller di visualizzazione.

Per verificare se il controller di visualizzazione "è il controller della vista dall'alto" è abbastanza diverso da "è visibile", è necessario controllare lo stack del controller di visualizzazione del controller di navigazione del controller di visualizzazione.

Ho scritto un pezzo di codice per risolvere questo problema:

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

Bel post! FYI isViewLoadedè una proprietà dal Swift 3.0.
Yuchen Zhong,

28

Si desidera utilizzare la UITabBarController's selectedViewControllerproprietà. Tutti i controller di visualizzazione collegati a un controller della barra delle schede hanno un tabBarControllerset di proprietà, quindi è possibile, all'interno di qualsiasi codice del controller di visualizzazione:

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

2
Ciò non funziona se il controller di visualizzazione è contenuto all'interno di un controller di navigazione e tale controller viene aggiunto al controller della barra delle schede. La chiamata a SelectedViewController restituirà il controller di navigazione e non il controller di visualizzazione corrente.
Anton Holmberg,

2
@AntonHolmberg in quel caso, ottieni il controller vista visibile in questo modo:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
ma11hew28

Oppure usa la proprietà 'self.tabBarController.selectedIndex' se siamo andati così lontano.
Vladimir Shutyuk,

12

Ho fatto una rapida estensione in base alla risposta di @ progrmr.

Ti permette di controllare facilmente se uno UIViewControllerè sullo schermo in questo modo:

if someViewController.isOnScreen {
    // Do stuff here
}

L'estensione:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

7

Per i miei scopi, nel contesto di un controller di visualizzazione contenitore, l'ho trovato

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

funziona bene.


3

se stai utilizzando un UINavigationController e vuoi anche gestire le viste modali, utilizzo ciò che segue:

#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
Ho trovato questo modo più affidabile della risposta accettata, quando è disponibile un controller di navigazione. Questo può essere abbreviato in: if ([self.navigationController.visibleViewController isKindOfClass: [self class]]) {
Darren,

3

L'approccio che ho usato per un controller di visualizzazione presentato modale era di verificare la classe del controller presentato. Se il controller della vista presentato fosse ViewController2allora eseguirò del codice.

UIViewController *vc = [self presentedViewController];

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

3

Ho trovato quelle funzioni in 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);

Forse le funzioni di cui sopra possono rilevare la ViewControllercomparsa o meno.


3

XCode 6.4, per iOS 8.4, ARC abilitato

Ovviamente molti modi per farlo. Quello che ha funzionato per me è il seguente ...

@property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow

Questo può essere utilizzato in qualsiasi controller di visualizzazione nel modo seguente,

[self.view.window isKeyWindow]

Se chiami questa proprietà in -(void)viewDidLoadottieni 0, allora se la chiami dopo -(void)viewDidAppear:(BOOL)animatedaver ottenuto 1.

Spero che questo aiuti qualcuno. Grazie! Saluti.


3

Se stai usando un controller di navigazione e vuoi solo sapere se sei nel controller attivo e più in alto , usa:

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

Questa risposta si basa sul commento di @mattdipasquale .

Se hai uno scenario più complicato, vedi le altre risposte sopra.


questo non verrà mai chiamato se l'app passa in background e quindi in primo piano. Sto cercando una soluzione in cui posso verificare se il controller di visualizzazione è visibile all'utente o meno. L'utente può eseguire il background dell'app per alcuni giorni e quando torna in primo piano, vorrei aggiornare l'interfaccia utente. Per favore fammi sapere se puoi aiutare.
bibscy,

2

puoi verificarlo per windowproprietà

if(viewController.view.window){

// view visible

}else{

// no visible

}

0

Avevo bisogno di questo per verificare se il controller di visualizzazione è il controller visualizzato corrente, l'ho fatto controllando se c'è un controller di visualizzazione presentato o inviato tramite il navigatore, lo sto pubblicando nel caso in cui qualcuno avesse bisogno di una tale soluzione:

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

0

Uso questa piccola estensione in Swift 5 , che lo rende semplice e facile da controllare per qualsiasi oggetto membro di UIView .

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

Quindi, lo uso solo come un semplice controllo if statement ...

if myView.isVisible {
    // do something
}

Spero possa essere d'aiuto! :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.