Bagaimana cara mengetahui apakah tampilan UIViewController terlihat

Jawaban:

1098

Properti jendela tampilan adalah nihil jika tampilan saat ini terlihat, jadi periksa tampilan utama di pengontrol tampilan:

Menjalankan metode tampilan menyebabkan tampilan memuat (jika tidak dimuat) yang tidak perlu dan mungkin tidak diinginkan. Akan lebih baik untuk memeriksa dulu untuk melihat apakah sudah dimuat. Saya telah menambahkan panggilan ke isViewLoaded untuk menghindari masalah ini.

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

Sejak iOS9 menjadi lebih mudah:

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

Atau jika Anda memiliki UINavigationController yang mengelola pengontrol tampilan, Anda dapat memeriksa properti visibleViewControllernya .

program
sumber
11
Masalah dengan properti visibleViewControllee UINavigationController's adalah kasus di mana visibleViewController Anda menyajikan pengontrol tampilan modal. Dalam hal itu, tampilan modal menjadi visibleViewController, yang mungkin tidak diinginkan. Bagaimana Anda menanganinya?
Moshe
12
Ini mungkin jelas bagi semua orang, tetapi bagi saya kodenya harus berupa self.isViewLoaded && self.view.window
JeffB6688
85
Hati-hati dalam menggeneralisasi solusi ini ke situasi lain. Misalnya, jika Anda menggunakan UIPageViewController, tampilan untuk UIViewControllers yang bukan halaman saat ini mungkin masih memiliki properti jendela non-nil karena sedang dirender di luar layar. Dalam hal ini, saya telah berhasil membuat properti 'isCurrentlyVisible' saya sendiri yang akan diatur dalam viewDidAppear dan viewDidDisappear.
evanflash
4
@ Moshe dalam hal ini, gunakan topViewController.
ma11hew28
3
Harap perhatikan bahwa jawaban ini tidak mengatakan apa pun tentang visibilitas nyata. Misalnya, jika aplikasi berada di latar belakang di atas, pernyataan IF akan mengatakan YA sementara tampilan tidak benar-benar terlihat.
Marek J.
89

Inilah solusi @ progrmr sebagai UIViewControllerkategori:

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

Ada beberapa masalah dengan solusi di atas. Jika Anda menggunakan, misalnya, a UISplitViewController, tampilan master akan selalu benar untuk

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

Sebagai gantinya, ambil pendekatan sederhana ini yang tampaknya bekerja dengan baik di sebagian besar, jika tidak semua kasus:

- (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
sumber
1
Apakah ini masih berlaku di xCode 7.1.1? Master di UISplitViewController saya mengembalikan TIDAK untuk viewController.view.window. Saya mungkin melakukan sesuatu yang salah, tetapi saya cukup yakin inilah masalahnya.
SAHM
44

Bagi Anda yang mencari versi Swift 2.2 dari jawabannya:

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

dan Swift 3 :

if self.isViewLoaded && (self.view.window != nil) {
         // viewController is visible
}
Benjamin
sumber
Tidak yakin mengapa, tetapi saya menemukan bahwa melakukan self.view.window! = Nil menyebabkannya tidak pernah berfungsi meskipun self.isViewLoaded benar. Setelah dihapus, itu berfungsi dengan baik.
Micah Montoya
ini hanya berfungsi untuk saya di viewDidAppear. Ketika saya menambahkan ini ke viewWillAppear self.view.window! = Nil selalu muncul nihil
Lance Samaria
29

Untuk presentasi moda over-layar penuh atau over-konteks, "terlihat" bisa berarti itu di atas tumpukan pengontrol tampilan atau hanya terlihat tetapi ditutupi oleh pengontrol tampilan lain.

Untuk memeriksa apakah pengontrol tampilan "adalah pengontrol tampilan atas" sangat berbeda dari "terlihat", Anda harus memeriksa tumpukan pengendali tampilan pengendali navigasi pengendali view controller.

Saya menulis sepotong kode untuk mengatasi masalah ini:

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
sumber
Pos yang bagus! FYI isViewLoadedadalah properti sejak Swift 3.0.
Yuchen Zhong
28

Anda ingin menggunakan properti UITabBarController's selectedViewController. Semua pengontrol tampilan yang terlampir pada pengontrol bilah tab memiliki tabBarControllerproperti yang diatur, jadi Anda bisa, dari dalam kode pengontrol tampilan apa pun:

if([[[self tabBarController] selectedViewController] isEqual:self]){
     //we're in the active controller
}else{
     //we are not
}
pelaksana21
sumber
2
Ini tidak berfungsi jika pengontrol tampilan terdapat di dalam pengontrol navigasi dan pengontrol itu ditambahkan ke pengontrol tab bar. Panggilan ke selectedViewController akan mengembalikan pengontrol navigasi dan bukan pengontrol tampilan saat ini.
Anton Holmberg
2
@AntonHolmberg dalam kasus itu, dapatkan pengontrol tampilan yang terlihat seperti ini:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
ma11hew28
Atau bahkan menggunakan properti 'self.tabBarController.selectedIndex' jika kita sudah sejauh ini.
Vladimir Shutyuk
12

Saya membuat ekstensi cepat berdasarkan jawaban @ progrmr.

Ini memungkinkan Anda untuk dengan mudah memeriksa apakah UIViewControllerada di layar seperti:

if someViewController.isOnScreen {
    // Do stuff here
}

Ekstensi:

//
//  UIViewControllerExtension.swift
//

import UIKit

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

Untuk tujuan saya, dalam konteks pengontrol tampilan wadah, saya telah menemukan itu

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

bekerja dengan baik.

Chris Prince
sumber
3

jika Anda menggunakan UINavigationController dan juga ingin menangani tampilan modal, berikut ini yang saya gunakan:

#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
}
Tn. Kristan
sumber
2
Saya menemukan cara ini lebih dapat diandalkan daripada jawaban yang diterima, ketika pengontrol navigasi tersedia. Ini dapat disingkat menjadi: if ([self.navigationController.visibleViewController isKindOfClass: [self class]]) {
Darren
3

Pendekatan yang saya gunakan untuk modal yang disajikan view controller adalah untuk memeriksa kelas controller yang disajikan. Jika controller tampilan yang disajikan adalah ViewController2maka saya akan menjalankan beberapa kode.

UIViewController *vc = [self presentedViewController];

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

Saya menemukan fungsi tersebut di 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);

Mungkin fungsi di atas bisa mendeteksi ViewControllermuncul atau tidak.

AechoLiu
sumber
3

XCode 6.4, untuk iOS 8.4, ARC diaktifkan

Jelas banyak cara untuk melakukannya. Salah satu yang telah bekerja untuk saya adalah sebagai berikut ...

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

Ini dapat digunakan di pengontrol tampilan apa pun dengan cara berikut,

[self.view.window isKeyWindow]

Jika Anda memanggil properti ini di dalam -(void)viewDidLoadAnda mendapatkan 0, maka jika Anda memanggil ini setelah -(void)viewDidAppear:(BOOL)animatedAnda mendapatkan 1.

Semoga ini bisa membantu seseorang. Terima kasih! Bersulang.

serge-k
sumber
3

Jika Anda menggunakan pengontrol navigasi dan hanya ingin tahu apakah Anda berada di pengontrol aktif dan teratas , maka gunakan:

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

Jawaban ini didasarkan pada komentar @mattdipasquale .

Jika Anda memiliki skenario yang lebih rumit, lihat jawaban lain di atas.

Phatmann
sumber
ini tidak akan pernah dipanggil jika aplikasi berjalan di latar belakang dan kemudian di latar depan. Saya mencari solusi di mana saya dapat memeriksa apakah pengontrol tampilan dapat dilihat oleh pengguna atau tidak. Pengguna dapat latar aplikasi selama beberapa hari dan ketika kembali di latar depan, saya ingin memperbarui UI. Harap beritahu saya bila Anda dapat membantu.
bibscy
2

Anda dapat memeriksanya menurut windowproperti

if(viewController.view.window){

// view visible

}else{

// no visible

}
Saad Ur Rehman
sumber
0

Saya memerlukan ini untuk memeriksa apakah view controller adalah controller yang dilihat saat ini, saya melakukannya dengan memeriksa apakah ada controller tampilan yang disajikan atau didorong melalui navigator, saya mempostingnya jika ada yang membutuhkan solusi seperti itu:

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

Saya menggunakan ekstensi kecil ini di Swift 5 , yang membuatnya sederhana dan mudah untuk memeriksa objek apa pun yang merupakan anggota UIView .

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

Kemudian, saya hanya menggunakannya sebagai pernyataan ...

if myView.isVisible {
    // do something
}

Saya harap ini membantu! :)

valbu17
sumber