So erkennen Sie, ob die Ansicht von UIViewController sichtbar ist

570

Ich habe eine Tab-Leisten-Anwendung mit vielen Ansichten. Gibt es eine Möglichkeit zu wissen, ob eine bestimmte UIViewControllerPerson derzeit in der UIViewControllerUmgebung sichtbar ist ? (auf der Suche nach einer Immobilie)

Rob Bonner
quelle
Verwandte: Holen
Sie sich

Antworten:

1098

Die Fenstereigenschaft der Ansicht ist nicht Null, wenn eine Ansicht derzeit sichtbar ist. Überprüfen Sie daher die Hauptansicht im Ansichts-Controller:

Durch Aufrufen der Ansichtsmethode wird die Ansicht geladen (sofern sie nicht geladen ist), was nicht erforderlich und möglicherweise unerwünscht ist. Es ist besser, zuerst zu überprüfen, ob es bereits geladen ist. Ich habe den Aufruf von isViewLoaded hinzugefügt, um dieses Problem zu vermeiden.

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

Seit iOS9 ist es einfacher geworden:

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

Wenn Sie einen UINavigationController haben, der die Ansichtscontroller verwaltet, können Sie stattdessen die Eigenschaft visibleViewController überprüfen .

Progrmr
quelle
11
Das einzige Problem mit der VisibleViewControllee-Eigenschaft eines UINavigationControllers ist der Fall, in dem Ihr VisibleViewController einen Modal View Controller darstellt. In diesem Fall wird die modale Ansicht zum sichtbaren ViewController, was möglicherweise unerwünscht ist. Wie würden Sie damit umgehen?
Moshe
12
Dies ist wahrscheinlich für alle offensichtlich, aber für mich musste der Code self.isViewLoaded && self.view.window sein
JeffB6688
85
Seien Sie vorsichtig, wenn Sie diese Lösung auf andere Situationen übertragen. Wenn Sie beispielsweise einen UIPageViewController verwenden, haben Ansichten für UIViewController, die nicht die aktuelle Seite sind, möglicherweise immer noch eine Nicht-Null-Fenstereigenschaft, da sie außerhalb des Bildschirms gerendert werden. In diesem Fall hatte ich Erfolg damit, meine eigene Eigenschaft 'isCurrentlyVisible' zu erstellen, die in viewDidAppear und viewDidDisappear festgelegt wird.
Evansflash
4
@ Moshe in diesem Fall verwenden topViewController.
ma11hew28
3
Bitte beachten Sie, dass diese Antwort nichts über die tatsächliche Sichtbarkeit aussagt. Befindet sich die App beispielsweise im Hintergrund über der IF-Anweisung, wird JA angezeigt, während die Ansicht nicht wirklich sichtbar ist.
Marek J.
89

Hier ist die Lösung von @progrmr als UIViewControllerKategorie:

// 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
ma11hew28
quelle
47

Bei den oben genannten Lösungen gibt es einige Probleme. Wenn Sie beispielsweise a verwenden UISplitViewController, gibt die Masteransicht immer true für zurück

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

Verwenden Sie stattdessen diesen einfachen Ansatz, der in den meisten, wenn nicht allen Fällen gut zu funktionieren scheint:

- (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;
}
vincentjames501
quelle
1
Trifft dies in xCode 7.1.1 noch zu? Der Master in meinem UISplitViewController gibt NO für viewController.view.window zurück. Ich mache vielleicht etwas falsch, aber ich bin mir ziemlich sicher, dass dies der Fall ist.
SAHM
44

Für diejenigen unter Ihnen, die nach einer Swift 2.2- Version der Antwort suchen :

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

und Swift 3 :

if self.isViewLoaded && (self.view.window != nil) {
         // viewController is visible
}
Benjamin
quelle
Ich bin mir nicht sicher warum, aber ich habe festgestellt, dass self.view.window! = Nil dazu führt, dass es niemals funktioniert, selbst wenn self.isViewLoaded wahr ist. Einmal entfernt, funktioniert es gut.
Micah Montoya
Dies funktionierte nur bei mir in viewDidAppear. Als ich dies zu viewWillAppear hinzufügte self.view.window! = Nil kam immer nil
Lance Samaria
29

Bei einer modalen Darstellung im Vollbildmodus oder im Kontext kann "sichtbar" bedeuten, dass sie sich über dem Stapel des Ansichtscontrollers befindet oder nur sichtbar ist, aber von einem anderen Ansichtscontroller abgedeckt wird.

Um zu überprüfen, ob der Ansichts-Controller "der Draufsicht-Controller ist" sich stark von "sichtbar" unterscheidet, sollten Sie den Ansichts-Controller-Stapel des Navigations-Controllers des Ansichts-Controllers überprüfen.

Ich habe einen Code geschrieben, um dieses Problem zu lösen:

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
        }
    }
}
WeZZard
quelle
Netter Post! FYI isViewLoadedist eine Eigenschaft seit Swift 3.0.
Yuchen Zhong
28

Sie möchten die verwenden UITabBarController‚s - selectedViewControllerEigenschaft. Alle an einen Registerkarten-Controller angehängten Ansichts-Controller verfügen über einen tabBarControllerEigenschaftssatz, sodass Sie in jedem Code der Ansichts-Controller Folgendes tun können:

if([[[self tabBarController] selectedViewController] isEqual:self]){
     //we're in the active controller
}else{
     //we are not
}
executor21
quelle
2
Dies funktioniert nicht, wenn der Ansichts-Controller in einem Navigations-Controller enthalten ist und dieser Controller dem Registerkarten-Controller hinzugefügt wird. Der Aufruf von selectedViewController gibt den Navigationscontroller und nicht den aktuellen View Controller zurück.
Anton Holmberg
2
@AntonHolmberg in diesem Fall erhalten Sie die sichtbare Ansicht Controller wie ((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
folgt
Oder verwenden Sie sogar die Eigenschaft 'self.tabBarController.selectedIndex', wenn wir so weit gegangen sind.
Vladimir Shutyuk
12

Ich habe eine schnelle Erweiterung basierend auf der Antwort von @progrmr vorgenommen.

Damit können Sie einfach überprüfen, ob a wie UIViewControllerfolgt auf dem Bildschirm angezeigt wird:

if someViewController.isOnScreen {
    // Do stuff here
}

Die Erweiterung:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

Für meine Zwecke habe ich das im Kontext eines Container View Controllers gefunden

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

funktioniert gut.

Chris Prince
quelle
3

Wenn Sie einen UINavigationController verwenden und auch modale Ansichten verarbeiten möchten, verwende ich Folgendes:

#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
}
MrTristan
quelle
2
Ich habe festgestellt, dass dieser Weg zuverlässiger ist als die akzeptierte Antwort, wenn ein Navigationscontroller verfügbar ist. Dies kann verkürzt werden zu: if ([self.navigationController.visibleViewController isKindOfClass: [self class]]) {
Darren
3

Der Ansatz, den ich für einen modalen Controller für präsentierte Ansichten verwendet habe, bestand darin, die Klasse des präsentierten Controllers zu überprüfen. Wenn der vorgestellte View Controller ViewController2wäre, würde ich Code ausführen.

UIViewController *vc = [self presentedViewController];

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

Ich habe diese Funktion in gefunden 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);

Möglicherweise können die oben genannten Funktionen erkennen, ob das angezeigt ViewControllerwird oder nicht.

AechoLiu
quelle
3

XCode 6.4, für iOS 8.4, ARC aktiviert

Offensichtlich viele Möglichkeiten, dies zu tun. Derjenige, der für mich gearbeitet hat, ist der folgende ...

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

Dies kann in jedem View Controller auf folgende Weise verwendet werden:

[self.view.window isKeyWindow]

Wenn Sie diese Eigenschaft in aufrufen, erhalten -(void)viewDidLoadSie 0, und wenn Sie dies aufrufen, nachdem -(void)viewDidAppear:(BOOL)animatedSie 1 erhalten haben.

Hoffe das hilft jemandem. Vielen Dank! Prost.

serge-k
quelle
3

Wenn Sie einen Navigationscontroller verwenden und nur wissen möchten, ob Sie sich im aktiven und obersten Controller befinden, verwenden Sie:

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

Diese Antwort basiert auf dem Kommentar von @mattdipasquale .

Wenn Sie ein komplizierteres Szenario haben, lesen Sie die anderen Antworten oben.

Phatmann
quelle
Dies wird niemals aufgerufen, wenn die App im Hintergrund und dann im Vordergrund steht. Ich suche nach einer Lösung, mit der ich überprüfen kann, ob der View Controller für den Benutzer sichtbar ist oder nicht. Der Benutzer kann die App für einige Tage im Hintergrund speichern. Wenn sie wieder im Vordergrund steht, möchte ich die Benutzeroberfläche aktualisieren. Bitte lassen Sie mich wissen, wenn Sie helfen können.
bibscy
2

Sie können es durch windowEigenschaft überprüfen

if(viewController.view.window){

// view visible

}else{

// no visible

}
Saad Ur Rehman
quelle
0

Ich brauchte dies, um zu überprüfen, ob der Ansichts-Controller der aktuell angezeigte Controller ist. Ich habe dies getan, indem ich überprüft habe, ob ein Ansichts-Controller angezeigt oder durch den Navigator geschoben wurde. Ich poste ihn, falls jemand eine solche Lösung benötigt:

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

Ich verwende diese kleine Erweiterung in Swift 5 , mit der es einfach und leicht ist, nach Objekten zu suchen , die Mitglied von UIView sind .

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

Dann benutze ich es einfach als einfache if-Anweisungsprüfung ...

if myView.isVisible {
    // do something
}

Ich hoffe, es hilft! :) :)

valbu17
quelle