Odpowiedzi:
Ponieważ modalViewController
została wycofana w iOS 6, oto wersja, która działa na iOS 5+ i która kompiluje się bez ostrzeżeń.
Cel C:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
Szybki:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
Cynk kapelusza do odpowiedzi Felipe.
nil == nil
zwraca YES
, a nie jest to wynik, którego chcemy.
Jeśli szukasz systemu iOS 6+, ta odpowiedź jest przestarzała i powinieneś sprawdzić odpowiedź Gabriele Petronella
Nie ma na to zgrabnego sposobu, ponieważ jest to właściwość lub metoda natywna dla UIKit. Możesz sprawdzić kilka aspektów swojego kontrolera, aby upewnić się, że jest on przedstawiony jako modalny.
Tak więc, aby sprawdzić, czy obecny (przedstawiony self
w kodzie poniżej) kontroler jest przedstawiony w sposób modalny, czy nie, mam poniżej funkcję albo w UIViewController
kategorii, albo (jeśli twój projekt nie musi używać innych kontrolerów UIKit, jak UITableViewController
na przykład) w kontrolerze podstawowym, który dziedziczą moje inne kontrolery
-(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;
}
EDYCJA: Dodałem ostatnie sprawdzenie, czy używany jest UITabBarController, i przedstawiasz inny UITabBarController jako modalny.
EDYCJA 2: dodano kontrolę iOS 5+, gdzie UIViewController
już nie odpowiada parentViewController
, ale presentingViewController
zamiast tego.
EDYCJA 3: Stworzyłem dla niego sedno na wszelki wypadek https://gist.github.com/3174081
modalViewController
właściwość jest przestarzała od wersji iOS 6. Dokumentacja sugeruje jej użycie presentedViewController
.
NSLog(@"%@", self.navigationController.parentViewController)
wydruki (null)
- czy mógłbyś wyjaśnić dlaczego? Mój ViewController jest połączony z kontrolerem widoku modalnego poprzez navController w scenorysie.
.parentViewController
jest przestarzały, .presentingViewController
należy go zamiast tego użyć.
W iOS5 +, jak widać w odwołaniu do klasy UIViewController , można je pobrać z właściwości „ presentViewController ”.
PresentViewController Kontroler widoku, który przedstawił ten kontroler widoku. (tylko czytać)
@property (nonatomic, readonly) UIViewController * presentViewController
Discussion
Jeśli kontroler widoku, który odebrał ten komunikat, jest prezentowany przez inny kontroler widoku, ta właściwość zawiera kontroler widoku, który go przedstawia. Jeśli kontroler widoku nie jest prezentowany, ale prezentowany jest jeden z jego przodków, ta właściwość przechowuje kontroler widoku przedstawiający najbliższego przodka. Jeśli nie jest przedstawiony ani kontroler widoku, ani żaden z jego przodków, ta właściwość jest zerowa.
Dostępność
Dostępne w iOS 5.0 i nowszych.
Zadeklarowane w
UIViewController.h
presentingViewController
. Będzie również działać w kontrolerach widoku kontenera, ponieważ automatycznie przechodzi przez przodków.
Jeśli tak nie jest, możesz zdefiniować właściwość this ( presentedAsModal
) w podklasie UIViewController i ustawić ją na YES
przed przedstawieniem ViewController jako widoku modalnego.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Możesz sprawdzić tę wartość w swoim viewWillAppear
nadpisaniu.
Uważam, że nie ma oficjalnej właściwości określającej sposób prezentacji widoku, ale nic nie stoi na przeszkodzie, aby utworzyć własny.
UINavigationController
jako modalne ... chyba że utworzysz niestandardowy kontroler nawigacji tylko po to, aby dodać tę właściwość. A potem, wewnątrz kontrolerów, będziesz musiał przesyłać self.navigationController
do tej niestandardowej klasy za każdym razem, gdy będziesz musiał sprawdzić, czy kontroler jest prezentowany jako modalny
Odpowiedź Petronelli nie działa, jeśli self.navigationController jest prezentowane modalnie, ale self nie jest równe self.navigationController.viewControllers [0], w tym przypadku self jest wypychane.
Oto, jak możesz rozwiązać problem.
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]];
A w Swift:
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
|| self.tabBarController?.presentingViewController is UITabBarController
To powinno działać.
if(self.parentViewController.modalViewController == self)…
UINavigationController
i UITabBarController
. Jak na razie działa całkiem nieźle
Najlepszy sposób na sprawdzenie
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
Jeśli nie musisz rozróżniać między pełnoekranowymi widokami modalnymi a widokami niemodalnymi, co ma miejsce w moim projekcie (miałem do czynienia z problemem, który występuje tylko w przypadku arkuszy formularzy i arkuszy stron), możesz skorzystać z modalPresentationStyle właściwość UIViewController:
switch (self.modalPresentationStyle) {
case 0: NSLog(@"full screen, or not modal"); break;
case 1: NSLog(@"page sheet"); break;
case 2: NSLog(@"form sheet"); break;
}
W 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
}
W moim projekcie mam kontroler widoku (Szczegóły), który może być prezentowany modalnie (podczas dodawania nowego elementu) lub za pomocą push (podczas edycji istniejącego) przez kontroler widoku Master. Gdy użytkownik naciśnie przycisk [Gotowe], kontroler widoku szczegółowego wywołuje metodę kontrolera widoku głównego, aby powiadomić, że jest gotowy do zamknięcia. Mistrz musi określić, w jaki sposób przedstawiony jest szczegół, aby wiedzieć, jak go zamknąć. Oto jak to robię:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
Taki hack może zadziałać.
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
}
Myślę jednak, że moja poprzednia odpowiedź jest czystszym rozwiązaniem.
To, co dla mnie zadziałało, to:
// 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);
O ile to przetestowałem, działa to na iOS7 i iOS8. Nie próbowałem jednak na iOS6.
Rozejrzałem się trochę, aby znaleźć właściwą odpowiedź na to pytanie i nie mogłem znaleźć żadnej, która obejmowałaby wszystkie możliwe scenariusze. Napisałem kilka wierszy kodu, które wydają się działać. Możesz znaleźć kilka komentarzy w tekście, aby dowiedzieć się, co zostało sprawdzone.
- (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;
}
Mam nadzieję, że to pomoże.
Oto moja zmodyfikowana wersja @ GabrielePetronella's isModal
, która działa z zawartymi kontrolerami widoku, ponieważ najpierw przechodzi w górę hierarchii parentViewController. Wyciągnęliśmy również kod do wielu wierszy, aby było jasne, co robi.
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
}