ViewController'ın Modal olarak sunulup sunulmadığını belirlemek mümkün mü?


Yanıtlar:


96

modalViewControllerİOS 6'da kullanımdan kaldırıldığından bu yana , iOS 5+ için çalışan ve uyarı olmadan derlenen bir sürümü burada bulabilirsiniz.

Objective-C:

- (BOOL)isModal {
    return self.presentingViewController.presentedViewController == self
      || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
      || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}

Swift:

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

Felipe'nin cevabına şapka bahşiş.


2
iyi yakaladım, uzun bir süre sonra tekrar kullanmak zorunda kaldım ve kullanımdan kaldırmanın gerçekleştiğini fark ettim ... Cevabımı düzenledim, böylece insanlar iOS 6+ kullanırken doğru kodu aramaya başlasın, teşekkürler
Felipe Sabino

10
Üst görünüm denetleyicisi, görünüm denetleyicimizin üzerine itildiği bir modal ise çalışmaz.
anlam-konular

2
Bir hata var, her iki tarafın da sıfır olup olmadığını kontrol etmeliyiz çünkü nil == nilgeri dönüyor YESve istediğimiz sonuç bu değil.
CocoaBob

1
@GabrielePetronella Yanıtı, yöntemin Swift uygulamasını da içerecek şekilde güncellememin bir sakıncası var mı?
Michael Şelalesi

1
@MichaelŞelale çok takdir edilecektir, teşekkürler
Gabriele Petronella

77

İOS 6+ arıyorsanız, bu cevap kullanımdan kaldırılmıştır ve Gabriele Petronella'nın cevabını kontrol etmelisiniz.


UIKit'e özgü bir özellik veya yöntem olarak bunu yapmanın düzgün bir yolu yoktur. Yapabileceğiniz şey, kontrolörünüzün modal olarak sunulduğundan emin olmak için çeşitli yönlerini kontrol etmektir.

Dolayısıyla, mevcut ( selfaşağıdaki kodda gösterildiği gibi ) denetleyicinin modsal bir şekilde sunulup sunulmadığını kontrol etmek için, aşağıdaki işlevi bir UIViewControllerkategoride veya (projenizin diğer UIKit denetleyicilerini kullanması gerekmiyorsa) UITableViewControllerörneğin) diğer denetleyicilerimin devraldığı bir temel denetleyicide

-(BOOL)isModal {

     BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) || 
            //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
            ( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) || 
            //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
            [[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);

    //iOS 5+
    if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {

        isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) || 
             //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
             (self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) || 
             //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
             [[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);

    }

    return isModal;        

}

DÜZENLEME: Bir UITabBarController'ın kullanılıp kullanılmadığını görmek için son kontrolü ekledim ve modal olarak başka bir UITabBarController sunuyorsunuz.

DÜZENLEME 2: artık UIViewControlleryanıt vermeyen parentViewController, presentingViewControllerbunun yerine iOS 5+ kontrolü eklendi .

DÜZENLEME 3: https://gist.github.com/3174081 durumunda bunun için bir öz oluşturdum


modalViewControllerÖzelliğin iOS 6 itibariyle kullanımdan kaldırıldığını unutmayın . Belgeler presentedViewControllerbunun yerine kullanılmasını önerir .
Bart Jacobs

@BartJacobs iyi nokta! Bu yanıta iOS6 yayınlandıktan sonra bakmadım, bu yüzden güncel olmayabilir. Haftanın ilerleyen günlerinde güncellemek için bazı testler yapmaya çalışacağım, tks!
Felipe Sabino

NSLog(@"%@", self.navigationController.parentViewController)baskılar (null)- lütfen nedenini açıklar mısınız? My ViewController, film şeridindeki navController aracılığıyla modal görünüm denetleyicisine bağlanır.
Roman

@oyatek pastebin veya benzeri bir şey kullanabilir ve bazı kodlar gösterebilir misiniz?
Felipe Sabino

@Feilpe Sorunu buldum - .parentViewControllerkullanımdan kaldırıldı, .presentingViewControlleronun yerine kullanılmalı.
Roman

35

İOS5 + 'da, UIViewController Sınıf Başvurusu'nda görebileceğiniz gibi , bunu "presentingViewController" özelliğinden alabilirsiniz.

presentingViewController Bu görünüm denetleyicisini sunan görünüm denetleyicisi. (Sadece oku)

@property (nontomic, readonly) UIViewController * presentingViewController
Discussion

Bu mesajı alan görünüm denetleyicisi başka bir görünüm denetleyicisi tarafından sunulursa, bu özellik onu sunan görünüm denetleyicisini tutar. Görünüm denetleyicisi sunulmuyorsa, ancak atalarından biri sunuluyorsa, bu özellik en yakın atayı sunan görünüm denetleyicisini tutar. Ne görünüm denetleyicisi ne de onun atalarından biri sunulmuyorsa, bu özellik nil tutar.

Kullanılabilirlik
iOS 5.0 ve sonrasında mevcuttur. UIViewController.h'de
Bildirildi


3
Mükemmel çalışıyor, if (self.presentingViewController) {// Bu modal bir viewContoller} else {// Bu normal bir ViewController'dır}
mashdup

2
IMHO, buradaki tek doğru cevap bu . Sadece bir presentingViewController. Ataları otomatik olarak geçtiği için konteyner görünümü denetleyicilerinde de çalışacaktır.
Daniel Rinser

17

Eğer yoksa, presentedAsModalUIViewController alt sınıfınızda this ( ) için bir özellik tanımlayabilir YESve ViewController'ı modal bir görünüm olarak sunmadan önce bunu ayarlayabilirsiniz .

childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];

Bu değeri viewWillAppeargeçersiz kılmanızda kontrol edebilirsiniz .

Görüntünün nasıl sunulduğunu belirten resmi bir mülk olmadığına inanıyorum, ancak hiçbir şey sizi kendi görünümünüzü yaratmaktan alıkoyamıyor.


Doğru ve yaptığım şey bu ama başka bir temiz çözüm arıyordum. Teşekkürler.
lukewar

UINavigationControllerSadece bu özelliği eklemek için özel bir gezinti denetleyicisi oluşturmadığınız sürece, ... modal olarak sunuyorsanız bu çözüm çalışmaz . Ve bundan sonra, denetleyicilerin içinde, denetleyicinin self.navigationControllermodal olarak sunulup sunulmadığını her kontrol etmeniz gerektiğinde bu özel sınıfa yayınlamaya devam etmeniz gerekecek
Felipe Sabino

8

Eğer self.navigationController modsal olarak sunulursa, ancak self, self.navigationController.viewControllers [0] 'a eşit değilse, bu durumda self'e basıldığında Petronella'nın cevabı işe yaramaz.

İşte sorunu nasıl çözebileceğiniz.

return self.presentingViewController.presentedViewController == self
            || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
            || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];

Ve Swift'de:

return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
        || self.tabBarController?.presentingViewController is UITabBarController

6

Bu çalışmalı.

if(self.parentViewController.modalViewController == self)…

Maalesef bu işe yaramıyor. Bu benim ilk denememdi. Ancak modalViewController ins nil :(.
lukewar

Sadece 'self.parentViewController' alırsanız, doğru üst nesneyi döndürür mü?
kubi

4
Sorun, UIViewController alt sınıfınızın bir UINavigationController veya bir UITabBarController (veya her ikisi) içinde olması olabilir; bu durumda modal görünüm denetleyicisi olarak sunulan üst öğeyi bulmak için görünüm hiyerarşisinde biraz daha fazla araştırma yapmanız gerekebilir.
hpique

@hgpc Projemde bu chck'a ihtiyacım vardı, bu yüzden her ikisini de UINavigationControllerve UITabBarControllerdurumları kontrol etmek için bir cevap ekledim . Şu ana kadar oldukça iyi çalışıyor
Felipe Sabino

4

Kontrol etmenin en iyi yolu

 if (self.navigationController.presentingViewController) {
         NSLog(@"Model Present");
    }

2

Tam ekran modal görünümler ve modal olmayan görünümler arasında ayrım yapmanız gerekmiyorsa, ki projemdeki durum budur (yalnızca form sayfaları ve sayfa sayfalarında oluşan bir sorunla uğraşıyordum), modalPresentationStyle'ı kullanabilirsiniz. UIViewController özelliği:

switch (self.modalPresentationStyle) {
    case 0: NSLog(@"full screen, or not modal"); break;
    case 1: NSLog(@"page sheet"); break;
    case 2: NSLog(@"form sheet"); break;
}

2

In Swift :

func isUIViewControllerPresentedAsModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
        return true
    }

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}

Bu kullanım durumunda bir Sorun var. Bir UINavigationController'ın kök görünüm denetleyicisindeysem, herhangi bir modsal sunum olmadan yine de true döndürür.
mariusLAN

1
İlk if ifadesi, ikinci if ifadesindeki her şeyi kapsar ve ikinci ifadeyi gereksiz kılar. Buradaki niyetin ne olduğundan emin değilim.
isoiphone

1

Projemde, mod olarak (yeni bir öğe eklerken) veya Ana görünüm denetleyicisi tarafından (mevcut olanı düzenlerken) itme ile sunulabilen bir görünüm denetleyicisine (Ayrıntı) sahibim. Kullanıcı [Bitti] 'ye dokunduğunda, Detay görünüm denetleyicisi kapatılmaya hazır olduğunu bildirmek için Ana görünüm denetleyicisinin yöntemini çağırır. Kaptanın nasıl kapatılacağını bilmek için Ayrıntının nasıl sunulacağını belirlemesi gerekir. Ben bunu böyle yapıyorum:

UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
    [self dismissViewControllerAnimated:YES completion:NULL];
} else {
    [self.navigationController popViewControllerAnimated:YES];
}

0

Bunun gibi bir hack işe yarayabilir.

UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
    child = parent;
    parent = child.parentViewController;
}
if (parent) {
    // A view controller in the hierarchy was presented as a modal view controller
}

Ancak, önceki cevabımın daha temiz bir çözüm olduğunu düşünüyorum.


0

Benim için işe yarayan şey şudur:

// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;

// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);

// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];

// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);

Test ettiğim kadarıyla, bu iOS7 ve iOS8 için çalışıyor. Ancak iOS6'da denemedim.


0

Bu soruya doğru cevabı bulmak için biraz etrafa baktım ve olası tüm senaryoları kapsayan hiçbirini bulamadım. İşi yapıyor gibi görünen bu birkaç satır kod yazdım. Neyin kontrol edildiğini anlamak için birkaç satır içi yorum bulabilirsiniz.

- (BOOL)isModal {
    BOOL modal = NO;
    if ([self presentingViewController]) { //Some view Controller is presenting the current stack
        UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
        if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
            NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
            modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
        }
        else {
            modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
        }
    }
    return modal;
}

Umarım bu yardımcı olur.


0

İşte benim değiştirilmiş @ GabrielePetronella isModalsürümüm, ilk önce parentViewController hiyerarşisini yürüterek içerilen görünüm denetleyicileri ile çalışır. Ayrıca kodu birden çok satıra çekti, böylece ne yaptığı açık.

var isModal: Bool {
    // If we are a child view controller, we need to check our parent's presentation
    // rather than our own.  So walk up the chain until we don't see any parentViewControllers
    var potentiallyPresentedViewController : UIViewController = self
    while (potentiallyPresentedViewController.parentViewController != nil) {
        potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
    }

    if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController {
        return true
    }

    if let navigationController = potentiallyPresentedViewController.navigationController {
        if navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        }
    }

    return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}
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.