क्या यह निर्धारित करना संभव है कि क्या ViewController को मॉडल के रूप में प्रस्तुत किया गया है?


117

क्या ViewController वर्ग के अंदर यह जांचना संभव है कि इसे मोडल व्यू कंट्रोलर के रूप में प्रस्तुत किया जाए?

जवाबों:


96

चूंकि modalViewControllerआईओएस 6 में पदावनत किया गया है, यहां एक संस्करण है जो आईओएस 5+ के लिए काम करता है और जो चेतावनी के बिना संकलित करता है।

उद्देश्य सी:

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

स्विफ्ट:

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

फेलिप के जवाब के लिए हैट टिप।


2
अच्छी पकड़, मुझे बस लंबे समय के बाद फिर से इसका इस्तेमाल करना पड़ा और ध्यान दिया गया कि डिप्रैशन हुआ ... मैंने अपना उत्तर संपादित किया ताकि लोग iOS 6+ का उपयोग करते समय सही कोड की तलाश करें, धन्यवाद
फेलिप सबिनो

10
अगर पैरेंट व्यू कंट्रोलर एक मोडल है, जिस पर हमारा व्यू कंट्रोलर पुश नहीं करता है, तो यह काम नहीं करता है।
अर्थ-मायने

2
एक बग है, हमें जांच करनी चाहिए कि क्या दोनों पक्ष शून्य हैं, क्योंकि nil == nilरिटर्न YES, और यह वह परिणाम नहीं है जो हम चाहते हैं।
कोकोआ

1
@GabrielePetronella क्या आपको कोई आपत्ति है कि अगर मैं इस विधि का एक स्विफ्ट कार्यान्वयन शामिल करने के लिए उत्तर को अपडेट करता हूं?
माइकल झरना

1
@MichaelWaterfall कि बहुत सराहना की जाएगी, धन्यवाद
गेब्रियल पेट्रोनेला

77

यदि आप iOS 6+ की तलाश कर रहे हैं, तो यह उत्तर पदावनत है और आपको गेब्रियल पेट्रोनेला के उत्तर की जाँच करनी चाहिए


UIKit के लिए एक संपत्ति या विधि के रूप में ऐसा करने का कोई साफ तरीका नहीं है। यह सुनिश्चित करने के लिए कि आप क्या कर सकते हैं अपने नियंत्रक के कई पहलुओं की जाँच करें ताकि इसे मोडल के रूप में प्रस्तुत किया जा सके।

इसलिए, यह जांचने के लिए कि क्या करंट ( selfकोड बलो में दर्शाया गया है) कंट्रोलर को मोडल तरीके से प्रस्तुत किया गया है या नहीं, मेरे पास फंक्शन बलो है या तो एक UIViewControllerश्रेणी में, या (यदि आपके प्रोजेक्ट को अन्य यूकीट कंट्रोलर का उपयोग करने की आवश्यकता नहीं है, तो UITableViewControllerउदाहरण के लिए) एक आधार नियंत्रक में जो मेरे अन्य नियंत्रकों को विरासत में मिला है

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

}

संपादित करें: मैंने अंतिम चेक को यह देखने के लिए जोड़ा कि क्या UITabBarController का उपयोग किया जा रहा है, और आप एक और UITabBarController मॉडल के रूप में प्रस्तुत करते हैं।

EDIT 2: iOS 5+ चेक जोड़ा गया, जहां अब UIViewControllerऔर parentViewControllerनहीं, बल्कि इसका जवाब है presentingViewController

EDIT 3: मैंने इसके लिए केवल https://gist.github.com/3174081 मामले में एक जिस्ट बनाया है


ध्यान रखें कि modalViewControllerसंपत्ति आईओएस 6 के रूप में पदावनत है। प्रलेखन presentedViewControllerइसके बजाय उपयोग करने का सुझाव देता है ।
बार्ट जैकब्स

@BartJacobs अच्छी बात! IOS6 रिलीज के बाद मैंने इस जवाब को नहीं देखा, इसलिए यह अप-टू-डेट नहीं हो सकता है। मैं इसे अपडेट करने के लिए सप्ताह में कुछ परीक्षण करने की कोशिश करूंगा, tks!
फेलिप सबिनो

NSLog(@"%@", self.navigationController.parentViewController)प्रिंट (null)- आप कृपया समझा सकते हैं क्यों? मेरा ViewController स्टोरीबोर्ड में navController के माध्यम से मोडल व्यू कंट्रोलर के साथ जुड़ा हुआ है।
रोमन

@oyatek क्या आप पास्टबिन या कुछ समान का उपयोग कर सकते हैं और कुछ कोड दिखा सकते हैं?
फेलिप सबिनो

@Fepepe मैंने पाया कि समस्या - .parentViewControllerपदावनत है, .presentingViewControllerइसके बजाय इसका उपयोग किया जाना चाहिए।
रोमन

35

IOS5 + में, जैसा कि आप UIViewController Class Reference में देख सकते हैं , आप इसे प्रॉपर्टी "प्रेजेंटिव्यूक्रैड्रोलर" से प्राप्त कर सकते हैं।

presentingViewController दृश्य नियंत्रक जिसने यह दृश्य नियंत्रक प्रस्तुत किया है। (सिफ़ पढ़िये)

@property (गैर-परमाणु, आसानी से) UIViewController * presentingViewController
चर्चा

यदि यह संदेश प्राप्त करने वाला दृश्य नियंत्रक किसी अन्य दृश्य नियंत्रक द्वारा प्रस्तुत किया जाता है, तो यह गुण उस दृश्य नियंत्रक को रखता है जो इसे प्रस्तुत कर रहा है। यदि दृश्य नियंत्रक प्रस्तुत नहीं किया गया है, लेकिन इसके पूर्वजों में से एक को प्रस्तुत किया जा रहा है, तो यह संपत्ति निकटतम पूर्वज को प्रस्तुत करने वाला दृश्य नियंत्रक रखती है। यदि न तो दृश्य नियंत्रक और न ही इसके पूर्वजों को प्रस्तुत किया जा रहा है, तो यह संपत्ति शून्य है।

उपलब्धता
आईओएस 5.0 और बाद में उपलब्ध है। UIViewController.h में
घोषित किया गया


3
पूरी तरह से काम करता है, अगर (self.pretingViewController) का उपयोग करें {// यह एक मोडल व्यू है कॉन्टोलर} बाकी {// यह एक सामान्य
व्यू कॉन्ट्रोलर है

2
IMHO, यह यहाँ एकमात्र सही उत्तर है। बस एक की उपस्थिति के लिए जाँच करें presentingViewController। यह कंटेनर दृश्य नियंत्रकों में भी काम करेगा, क्योंकि यह स्वचालित रूप से पूर्वजों का पता लगाता है।
डैनियल रिंसर

17

यदि ऐसा नहीं है, तो आप presentedAsModalअपने UIViewController उपवर्ग में इसके लिए ( ) संपत्ति को परिभाषित कर सकते हैं और YESViewController को एक दृश्य के रूप में प्रस्तुत करने से पहले इसे सेट कर सकते हैं।

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

आप अपने viewWillAppearओवरराइड में इस मान की जाँच कर सकते हैं।

मेरा मानना ​​है कि कोई आधिकारिक संपत्ति नहीं है जो बताती है कि दृश्य कैसे प्रस्तुत किया जाता है, लेकिन कुछ भी आपको अपना स्वयं का निर्माण करने से रोकता है।


RIght और यह वही है जो मैंने किया है, लेकिन मैं किसी अन्य स्वच्छ समाधान की तलाश में था। धन्यवाद।
गुनगुना

यदि आप एक UINavigationControllerमोडल के रूप में प्रस्तुत कर रहे हैं तो यह समाधान काम नहीं करता है ... जब तक कि आप केवल इस संपत्ति को जोड़ने के लिए एक कस्टम नेविगेशन नियंत्रक नहीं बनाते हैं। और उसके बाद, नियंत्रकों के अंदर, आपको self.navigationControllerहर बार इस कस्टम वर्ग के लिए कास्टिंग रखना होगा कि आपको यह जांचना है कि क्या नियंत्रक को मोडल के रूप में प्रस्तुत किया गया है
फेलिप सबिनो

8

पेट्रोनेला का जवाब काम नहीं करता है अगर self.navigationController को औपचारिक रूप से प्रस्तुत किया गया है, लेकिन स्वयं self.navigationController.viewControllers [0] के बराबर नहीं है, उस स्थिति में स्वयं को धक्का दिया जाता है।

यहां बताया गया है कि आप समस्या को कैसे ठीक कर सकते हैं।

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

और स्विफ्ट में:

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

यह काम करना चाहिए।

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

दुर्भाग्य से यह काम नहीं करता है। यह मेरी पहली कोशिश थी। लेकिन लौटे modalViewController ins nil :(।
गुनगुना

यदि आपको सिर्फ 'self.parentViewController' मिलता है तो क्या यह सही मूल वस्तु लौटाता है?
कुब्बी

4
समस्या यह हो सकती है कि आपका UIViewController उपवर्ग UINavigationController या UITabBarController (या दोनों) के अंदर है, जिस स्थिति में आपको माता-पिता को पता लगाने के लिए पदानुक्रम में थोड़ा और खुदाई करने की आवश्यकता हो सकती है, जिसे एक मॉडल दृश्य नियंत्रक के रूप में प्रस्तुत किया गया था।
hpique

@hgpc मुझे अपनी परियोजना में इस चाक की आवश्यकता थी, इसलिए मैंने दोनों UINavigationControllerऔर UITabBarControllerमामलों की जांच के लिए सिर्फ एक उत्तर जोड़ा । यह अब तक बहुत अच्छा काम कर रहा है
फेलिप सबिनो

4

जाँच करने का सबसे अच्छा तरीका

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

2

यदि आपको पूर्ण-स्क्रीन मोडल दृश्यों और गैर-मोडल विचारों के बीच अंतर करने की आवश्यकता नहीं है, जो कि मेरी परियोजना में है (मैं एक समस्या से निपट रहा था जो केवल फॉर्म शीट और पेज शीट के साथ होती है), आप modalPresentation.tyle का उपयोग कर सकते हैं 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;
}

2

में स्विफ्ट :

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
}

इस उपयोग के मामले में कोई समस्या है। अगर मैं एक UINavigationController के रूट व्यू कंट्रोलर में हूं तो यह बिना किसी मोडल प्रस्तुति के भी सही रहता है।
मार्सलैन

1
पहला यदि स्टेटमेंट सब कुछ कवर करता है जो कि दूसरे स्टेटमेंट में है, तो दूसरा स्टेटमेंट निरर्थक है। मुझे यकीन नहीं है कि यहाँ क्या इरादा है।
isoiphone

1

मेरे प्रोजेक्ट में मेरे पास एक व्यू कंट्रोलर (डिटेल) है जिसे मास्टर व्यू कंट्रोलर द्वारा या तो औपचारिक रूप से प्रस्तुत किया जा सकता है (जब कोई नया आइटम जोड़ रहा हो) या पुश के साथ (किसी मौजूदा को एडिट करते समय)। जब उपयोगकर्ता टैप करता है [हो गया] डिटेल व्यू कंट्रोलर मास्टर व्यू कंट्रोलर का तरीका बताता है कि यह बंद होने के लिए तैयार है। मास्टर को यह निर्धारित करना है कि इसे कैसे बंद किया जाए, यह जानने के लिए विस्तार से प्रस्तुत किया गया है। यह है कि मैं यह कैसे करते हैं:

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

0

इस तरह एक हैक काम कर सकता है।

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
}

हालांकि, मुझे लगता है कि मेरा पिछला जवाब एक क्लीनर समाधान है।


0

मेरे लिए क्या काम कर रहा है:

// 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);

जहाँ तक मैंने इसका परीक्षण किया है, यह iOS7 और iOS8 के लिए काम करता है। हालांकि iOS6 पर कोशिश नहीं की।


0

मैंने इस प्रश्न का सही उत्तर खोजने के लिए चारों ओर देखा है, और मुझे ऐसा कोई भी नहीं मिला, जो सभी संभावित परिदृश्यों को कवर करता हो। मैंने कोड की ये कुछ पंक्तियाँ लिखी हैं जो काम करती प्रतीत होती हैं। आपको पता लगाने के लिए कुछ इनलाइन टिप्पणियाँ मिल सकती हैं।

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

उममीद है कि इससे मदद मिलेगी।


0

यहाँ मेरा संशोधित संस्करण @ GabrielePetronella है isModal, जो इसमें सम्‍मिलित दृश्‍य नियंत्रकों के साथ काम करता है, जो पहले पैरेंटव्यूकंट्रोलर पदानुक्रम तक चलता है। साथ ही कोड को कई लाइनों में खींच लिया ताकि यह स्पष्ट हो जाए कि यह क्या कर रहा है।

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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.