UIViewController görünümünün görünür olup olmadığı nasıl anlaşılır


Yanıtlar:


1098

Bir görünüm şu anda görünür durumdaysa, görünümün window özelliği sıfır değildir, bu nedenle görünüm denetleyicisindeki ana görünümü kontrol edin:

Görünüm yönteminin çağrılması, görünümün yüklenmesine (yüklenmemişse) gereksizdir ve istenmeyen olabilir. Yüklü olup olmadığını ilk önce kontrol etmek daha iyi olur. Bu sorunu önlemek için isViewLoaded çağrısını ekledim.

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

İOS9'dan bu yana kolaylaştı:

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

Veya görünüm denetleyicilerini yöneten bir UINavigationController'ınız varsa, bunun yerine visibleViewController özelliğini denetleyebilirsiniz .


11
UINavigationController'ın visibleViewControllee özelliğiyle ilgili tek sorun, visibleViewController'ınızın kalıcı görünüm denetleyicisi sunduğu durumdur. Bu durumda, kalıcı görünüm, istenmeyen olabilecek visibleViewController olur. Bunu nasıl halledersin?
Moshe

12
Bu muhtemelen herkes için açıktır, ancak benim için kod self.isViewLoaded && self.view.window
JeffB6688

85
Bu çözümü diğer durumlara genelleme konusunda dikkatli olun. Örneğin, bir UIPageViewController kullanıyorsanız, geçerli sayfa olmayan UIViewControllers görünümleri ekran dışında işlendikleri için hala nil olmayan bir pencere özelliğine sahip olabilir. Bu durumda, viewDidAppear ve viewDidDisappear'da ayarlanan kendi 'isCurrentlyVisible' özelliğini oluşturmayı başardım.
evanflash

4
@Moshe bu durumda kullanın topViewController.
ma11hew28

3
Bu cevabın gerçek görünürlük hakkında hiçbir şey söylemediğini lütfen unutmayın. Örneğin, uygulama yukarıdaki arka planda ise, IF ifadesi görünüm gerçekten görünür olmasa da EVET diyecektir.
Marek J.

89

İşte UIViewControllerkategori olarak @ progrmr'nin çözümü :

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

Yukarıdaki çözümlerle ilgili birkaç sorun var. Örneğin a kullanıyorsanız, UISplitViewControllerana görünüm her zaman için doğru değerine dönecektir.

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

Bunun yerine, her durumda olmasa da çoğunda iyi işleyen bu basit yaklaşımı kullanın:

- (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
Bu xCode 7.1.1'de hala geçerli mi? Benim UISplitViewController içinde master viewController.view.window için NO döndürüyor. Yanlış bir şey yapıyor olabilirim, ama durumun bu olduğundan eminim.
SAHM

44

Cevabın Swift 2.2 sürümünü arayanlar için :

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

ve Swift 3 :

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

Neden emin değilim ama self.view.window! = Nil yapmanın self.isViewLoaded doğru olsa bile asla çalışmamasına neden olduğunu buldum. Bir kez kaldırıldı, iyi çalışıyor.
Micah Montoya

bu benim için sadece viewDidAppear'da çalıştı. Bunu viewWillAppear'a eklediğimde self.view.window! = Nil her zaman nil geldi
Lance Samaria

29

Tam ekran veya bağlam üstü modsal sunum için "görünür", görünüm denetleyici yığınının üstünde veya yalnızca görünür ancak başka bir görünüm denetleyicisi tarafından kapsanabilir anlamına gelebilir.

Görüntü denetleyicisinin "üstten görünüm denetleyicisi" olup olmadığını "görünür" den oldukça farklı olup olmadığını denetlemek için, görünüm denetleyicisinin gezinme denetleyicisinin görünüm denetleyicisi yığınını denetlemeniz gerekir.

Bu sorunu çözmek için bir parça kod yazdım:

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

Güzel mesaj! FYI isViewLoaded, Swift 3.0'dan beri bir özelliktir.
Yuchen Zhong

28

UITabBarControllerAdlı kullanıcının selectedViewControllerözelliğini kullanmak istiyorsunuz . Sekme çubuğu denetleyicisine bağlı tüm görünüm denetleyicilerinin bir tabBarControllerözellik kümesi vardır, böylece görünüm denetleyicilerinin kodlarının herhangi birinden şunları yapabilirsiniz:

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

2
Görünüm denetleyicisi bir gezinme denetleyicisinin içinde bulunuyorsa ve bu denetleyici sekme çubuğu denetleyicisine eklenmişse bu çalışmaz. Seçili ViewController çağrısı geçerli görünüm kontrolörünü değil, navigasyon kontrolörünü döndürecektir.
Anton Holmberg

2
@AntonHolmberg bu durumda, görünür görünüm denetleyicisini şu şekilde alın:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
ma11hew28

Ya da bu kadar ileri gidersek 'self.tabBarController.selectedIndex' özelliğini kullanın.
Vladimir Shutyuk

12

@ Progrmr'ın cevabına göre hızlı bir eklenti yaptım.

A'nın UIViewControllerekranda olup olmadığını kolayca kontrol etmenizi sağlar :

if someViewController.isOnScreen {
    // Do stuff here
}

Uzantı:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

7

Benim amacım için, bir konteyner görünümü denetleyicisi bağlamında,

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

iyi çalışıyor.


3

bir UINavigationController kullanıyorsanız ve aynı zamanda kalıcı görünümleri işlemek istiyorsanız, aşağıdakileri kullanıyorum:

#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
Bir navigasyon kontrol cihazı mevcut olduğunda bu yolun kabul edilen cevaptan daha güvenilir olduğunu buldum. Bu kısaltılabilir: if ([self.navigationController.visibleViewController isKindOfClass: [self class]])) {
Darren

3

Modsal bir görünüm denetleyicisi için kullandığım yaklaşım, sunulan denetleyicinin sınıfını kontrol etmekti. Sunulan görünüm denetleyicisi ViewController2olsaydı ben bazı kod yürütmek.

UIViewController *vc = [self presentedViewController];

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

3

Bu işlevi buldum 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);

Belki yukarıdaki fonksiyonlar ViewControllerbelirebilir ya da görünmez.


3

XCode 6.4, iOS 8.4 için, ARC etkin

Açıkçası bunu yapmanın birçok yolu. Benim için çalışan biri ...

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

Bu, herhangi bir görünüm denetleyicisinde aşağıdaki şekilde kullanılabilir,

[self.view.window isKeyWindow]

İçinde bu özelliği çağırırsanız -(void)viewDidLoad0 alırsınız, sonra -(void)viewDidAppear:(BOOL)animated1'i aldıktan sonra çağırırsanız .

Umarım bu birine yardımcı olur. Teşekkürler! Şerefe.


3

Bir gezinme denetleyicisi kullanıyorsanız ve yalnızca etkin ve en üstteki denetleyicide olup olmadığınızı öğrenmek istiyorsanız, şunu kullanın:

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

Bu cevap @mattdipasquale'nin yorumuna dayanmaktadır .

Daha karmaşık bir senaryonuz varsa, yukarıdaki diğer yanıtlara bakın.


uygulama arka planda ve sonra ön planda giderse bu çağrılmaz. Görünüm denetleyicisinin kullanıcı tarafından görülebilir olup olmadığını kontrol edebileceğim bir çözüm arıyorum. Kullanıcı birkaç gün boyunca uygulamayı arka plan olabilir ve geri geldiğinde, kullanıcı arayüzünü güncellemek istiyorum. Yardım edebileceksen bana bildir.
18:26

2

windowmülke göre kontrol edebilirsiniz

if(viewController.view.window){

// view visible

}else{

// no visible

}

0

Görünüm denetleyicisinin geçerli görüntülenen denetleyici olup olmadığını kontrol etmek için buna ihtiyacım vardı, sunulan herhangi bir görünüm denetleyicisi olup olmadığını kontrol ederek yaptım veya navigatörden itildim, herkes böyle bir çözüme ihtiyaç duyması durumunda gönderiyorum:

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

0

Bu küçük uzantıyı UIView üyesi olan herhangi bir nesneyi kontrol etmeyi basit ve kolay tutan Swift 5'te kullanıyorum .

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

Sonra, basit bir if ifadesi kontrolü olarak kullanıyorum ...

if myView.isVisible {
    // do something
}

Umut ediyorum bu yardım eder! :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.