Bagaimana cara memeriksa apakah pengontrol tampilan disajikan secara sederhana atau didorong pada tumpukan navigasi?


126

Bagaimana saya, dalam kode pengontrol tampilan, membedakan antara:

  • disajikan secara sederhana
  • mendorong tumpukan navigasi

Kedua presentingViewControllerdan isMovingToParentViewControlleryang YESdalam kedua kasus, sehingga tidak sangat membantu.

Yang memperumit masalah adalah bahwa pengontrol tampilan orang tua saya terkadang modal, di mana pengontrol tampilan yang akan diperiksa didorong.

Ternyata masalah saya adalah saya menyematkan saya HtmlViewControllerdi UINavigationControlleryang kemudian disajikan. Itulah mengapa upaya saya sendiri dan jawaban bagus di bawah ini tidak berhasil.

HtmlViewController*     termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;

modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
                   animated:YES
                 completion:nil];

Saya kira saya lebih baik memberi tahu pengontrol tampilan saya ketika itu modal, daripada mencoba menentukan.

Jawaban:


125

Ambil dengan sebutir garam, tidak diuji.

- (BOOL)isModal {
     if([self presentingViewController])
         return YES;
     if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
         return YES;
     if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
         return YES;

    return NO;
 }

12
Saya menemukan ini di posting SO lain. Namun, tidak berfungsi jika induk pengontrol tampilan yang didorong adalah modal; itulah situasi yang saya alami.
makna-hal

2
Seperti yang saya tulis, presentingViewControllerselalu YESdalam kasus saya; tidak membantu.
makna-hal

3
presentingViewControllerkembali YESuntuk VC yang didorong, ketika ada UITabBarControlleryang disetel sebagai root. Jadi, tidak cocok untuk kasus saya.
Yevhen Dubinin

5
Ini tidak berfungsi jika Anda menampilkan pengontrol tampilan kemudian mendorong yang lain.
Lee

3
"Ini tidak berfungsi jika Anda menampilkan pengontrol tampilan, lalu mendorong pengontrol lain." Bukan itu maksudnya, pengontrol tampilan yang didorong tidak ditampilkan.
Colin Swelin

87

Di Swift :

Tambahkan tanda untuk menguji apakah itu modal menurut jenis kelas:

// MARK: - UIViewController implementation

extension UIViewController {

    var isModal: Bool {

        let presentingIsModal = presentingViewController != nil
        let presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController
        let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController

        return presentingIsModal || presentingIsNavigation || presentingIsTabBar
    }
}

4
Seharusnya lebih baik di var, sepertivar isModal: Bool {}
malinois

1
@malinois diubah
YannSteph

Apa yang dilakukan falseparameter terakhir dalam returnpernyataan itu?
damjandd

Anda perlu mengubah agar presentingIsNavigation = navigationController? .presentingViewController? .presentedViewController == navigationController && navigationController! = nil
famfamfam

78

Anda diabaikan salah satu metode: isBeingPresented.

isBeingPresented adalah benar saat pengontrol tampilan disajikan dan salah saat didorong.

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if ([self isBeingPresented]) {
        // being presented
    } else if ([self isMovingToParentViewController]) {
        // being pushed
    } else {
        // simply showing again because another VC was dismissed
    }
}

2
Saya mencoba ini juga sebelum posting, dan itu tidak bekerja, isBeingPresentedadalah NO. Tapi saya melihat alasannya sekarang, saya menyematkan pengontrol tampilan saya yang disajikan di a UINavigationController, dan itulah yang saya dorong.
arti-hal

1
Anda tidak dapat mendorong pengontrol navigasi. Mungkin maksud Anda adalah menampilkan pengontrol navigasi.
rmaddy

3
@jowie Gunakan p, bukan posaat mencetak nilai primitif. poadalah untuk mencetak objek.
rmaddy

37
Dokumentasi untuk isBeingPresented- Metode ini mengembalikan YA hanya ketika dipanggil dari dalam metode viewWillAppear: dan viewDidAppear :.
funct7

4
@Terrence Tampaknya dokumentasi terbaru tidak menunjukkan informasi itu tetapi dulu ada di sana. The isBeingPresented, isBeingDismissed, isMovingFromParentViewControllerdan isMovingToParentViewControllerhanya berlaku dalam 4 view[Will|Did][Disa|A]ppearmetode.
rmaddy

29

Swift 5
Berikut adalah solusi yang membahas masalah yang disebutkan dengan jawaban sebelumnya, ketika isModal()pengembalian truejika didorong UIViewControllerdalam UINavigationControllertumpukan yang disajikan .

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if navigationController?.presentingViewController?.presentedViewController == navigationController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

Sejauh ini hal itu berhasil untuk saya. Jika beberapa pengoptimalan, silakan bagikan.


Mengapa Anda perlu memeriksa tabBarController?.presentingViewController is UITabBarController ? Apakah penting jika itu presentingViewControllerjuga UITabBarController?
Hlung

Dan jika navigationController nihil, isModalakan kembali true. Apakah ini dimaksudkan?
Hlung

28

self.navigationController! = nil berarti itu ada dalam tumpukan navigasi.

Untuk menangani kasus di mana pengontrol tampilan saat ini didorong sementara pengontrol navigasi disajikan secara sederhana, saya telah menambahkan beberapa baris kode untuk memeriksa apakah pengontrol tampilan saat ini adalah pengontrol root di tumpukan navigasi.

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if let navigationController = navigationController, navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        } else if let tabBarController = tabBarController, tabBarController.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

Secara umum, saat Anda menyajikan secara sederhana, Anda meletakkan viewController pada navigationController dan menampilkannya. Jika itu kasusnya pernyataan Anda akan salah, namun pada kode kasus ini ditangani. Harap perbaiki jawaban Anda :)
E-Riddie

pekerjaan bagus yang menangani semua kasus penggunaan. ruang untuk sedikit refactoring mungkin tapi masih upvote !!
Jean Raymond Daher

12

Cepat 4

var isModal: Bool {
    return presentingViewController != nil ||
           navigationController?.presentingViewController?.presentedViewController === navigationController ||
           tabBarController?.presentingViewController is UITabBarController
}

Swift 4.2 / iOS 12. Masih berfungsi dengan baik, tetapi ketahuilah bahwa navigationController? .PresentingViewController? .PresentedViewController === navigationController akan mengevaluasi ke true jika keduanya nihil (misalnya, jika Anda memanggilnya pada pengontrol tampilan yang belum disajikan).
Eli Burke

7

Cepat 5. Bersih dan sederhana.

if navigationController.presentingViewController != nil {
    // Navigation controller is being presented modally
}

1
ini melakukan trik untuk saya
Radu Ursache

3

Seperti yang disarankan oleh banyak orang di sini, bahwa metode "pemeriksaan" tidak berfungsi dengan baik untuk semua kasus, dalam proyek saya, saya telah menemukan solusi untuk mengelolanya secara manual. Intinya adalah, kita biasanya mengelola presentasi sendiri - bukan ini yang terjadi di belakang layar dan kita harus mawas diri.

DEViewController.h mengajukan:

#import <UIKit/UIKit.h>

// it is a base class for all view controllers within a project
@interface DEViewController : UIViewController 

// specify a way viewcontroller, is presented  by another viewcontroller
// the presented view controller should manually assign the value to it
typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) {
    SSViewControllerPresentationMethodUnspecified = 0,
    SSViewControllerPresentationMethodPush,
    SSViewControllerPresentationMethodModal,
};
@property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod;

// other properties/methods...
@end

Presentasi sekarang dapat diatur dengan cara ini:

didorong pada tumpukan navigasi:

// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];

disajikan secara sederhana dengan navigasi:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
                               initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];

disajikan secara sederhana:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];

Selain itu, di dalam DEViewControllerkita dapat menambahkan fallback ke "memeriksa" jika properti yang disebutkan di atas sama dengan SSViewControllerPresentationMethodUnspecified:

- (BOOL)isViewControllerPushed
{
    if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
        return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
    }

    else {
        // fallback to default determination method
        return (BOOL)self.navigationController.viewControllers.count > 1;
    }
}

3

Dengan asumsi bahwa semua viewController yang Anda sajikan secara sederhana dibungkus di dalam navigationController baru (yang harus selalu Anda lakukan), Anda dapat menambahkan properti ini ke VC Anda.

private var wasPushed: Bool {
    guard let vc = navigationController?.viewControllers.first where vc == self else {
        return true
    }

    return false
}

1
yang harus selalu Anda lakukan - tolong jelaskan mengapa?
Alexander Abakumov

Alexander, kamu tidak seharusnya, sungguh.
nickdnk

2

Untuk mendeteksi pengontrol Anda didorong atau tidak, cukup gunakan kode di bawah ini di mana pun Anda inginkan:

if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {

    // Not pushed
}
else {

    // Pushed
}

Saya harap kode ini dapat membantu siapa saja ...


1
Metode ini tidak berfungsi saat Anda menggunakan kelas pengontrol tampilan yang sama di banyak tempat, karena metode ini hanya memeriksa kelasnya. Sebagai gantinya, Anda dapat memeriksa kesetaraan secara eksplisit.
gklka

1

self.navigationController != nil berarti itu ada di tumpukan navigasi.


25
Masih dapat berada di pengontrol navigasi modal
ColdLogic

Jadi 'modal' dan 'push on navigation stack' tidak saling eksklusif. Berpikir ini tergantung pada konteksnya, tetapi memeriksa apakah self.navigationController tidak nihil tidak menjawab apakah itu pengontrol tampilan dari pengontrol navigasi.
Daniel

@Daniel Perbedaannya adalah antara "didorong" dan "disajikan". "Modal 'tidak ada hubungannya dengan itu. Saya percaya" ColdLogic "berarti" disajikan "ketika mereka mengatakan" modal ".
rmaddy

1
if let navigationController = self.navigationController, navigationController.isBeingPresented {
    // being presented
}else{
    // being pushed
}

0

Jika Anda menggunakan ios 5.0 atau lebih baru dari silakan gunakan kode ini

-(BOOL)isPresented
{
    if ([self isBeingPresented]) {
        // being presented
         return YES;
    } else if ([self isMovingToParentViewController]) {
        // being pushed
         return NO;
    } else {
        // simply showing again because another VC was dismissed
         return NO;
    }
}

0

Swift 5
Ekstensi praktis ini menangani lebih banyak kasus daripada jawaban sebelumnya. Kasus-kasus ini adalah VC (pengontrol tampilan) adalah root VC jendela aplikasi, VC ditambahkan sebagai anak ke induk VC. Ia mencoba mengembalikan true hanya jika viewcontroller disajikan secara sederhana.

extension UIViewController {
    /**
      returns true only if the viewcontroller is presented.
    */
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            if let parent = parent, !(parent is UINavigationController || parent is UITabBarController) {
                return false
            }
            return true
        } else if let navController = navigationController, navController.presentingViewController?.presentedViewController == navController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        }
        return false
    }
}

Terima kasih atas jawaban Jonauz . Sekali lagi ada ruang untuk lebih banyak pengoptimalan. Silakan diskusikan tentang kasus yang perlu ditangani di bagian komentar.


-1

Untuk beberapa orang yang bertanya-tanya, Bagaimana cara memberi tahu ViewController bahwa itu sedang disajikan

jika Amempresentasikan / mendorongB

  1. Tentukan enumdan propertydalamB

    enum ViewPresentationStyle {
        case Push
        case Present
    }
    
    //and write property 
    
    var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
  2. Sekarang dalam Apengontrol tampilan, beri tahu Bapakah itu disajikan / didorong dengan menetapkanpresentationStyle

    func presentBViewController() {
        let bViewController = B()
        bViewController.vcPresentationStyle = .Present //telling B that it is being presented
        self.presentViewController(bViewController, animated: true, completion: nil)
    }
  3. Penggunaan di BView Controller

    override func viewDidLoad() {
        super.viewDidLoad()
    
        if self.vcPresentationStyle == .Present {
            //is being presented 
        }
        else {
            //is being pushed
        }
    
    }

-2
id presentedController = self.navigationController.modalViewController;
if (presentedController) {
     // Some view is Presented
} else {
     // Some view is Pushed
}

Ini akan memberi tahu Anda jika viewController disajikan atau didorong


4
Properti ini tidak digunakan lagi.
Mork mulai
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.