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 .


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

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

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
}

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

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
}

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

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.


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
}

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

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.


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.


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.


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

}

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 
}

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! :)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.