IOS पर सबसे ऊपरी दृश्य नियंत्रक कैसे खोजें


253

मैंने अब कुछ ऐसे मामलों में भाग लिया है, जहाँ "सबसे ऊपरी" व्यू कंट्रोलर (करंट व्यू के लिए ज़िम्मेदार) को ढूंढना सुविधाजनक होगा, लेकिन इसे करने का कोई तरीका नहीं मिला है।

मूल रूप से चुनौती यह है: यह देखते हुए कि कोई व्यक्ति उस वर्ग में निष्पादित कर रहा है जो एक दृश्य नियंत्रक (या एक दृश्य) नहीं है [और एक सक्रिय दृश्य का पता नहीं है] और इसे सर्वोच्च दृश्य नियंत्रक के पते से पारित नहीं किया गया है ( या, कहें, नेविगेशन कंट्रोलर का पता), क्या उस व्यू कंट्रोलर को ढूंढना संभव है? (और, यदि हां, तो कैसे?)

या, यह असफल होना, क्या शीर्ष दृश्य को ढूंढना संभव है?


तो आप कह रहे हैं यह संभव नहीं है।
हॉट लिक्स

@ डैनियल नहीं, मैं कह रहा हूं कि ऐसा लगता है कि आपका कोड कुछ री-डिजाइनिंग का उपयोग कर सकता है, क्योंकि आपको यह जानने की आवश्यकता शायद ही हो। इसके अलावा, "सर्वोच्च" का विचार केवल कुछ संदर्भों में मान्य है, और फिर भी हमेशा नहीं।
डेव देलांग

@ डैनियल मैंने आपके सवाल को गलत बताया था। इस बात का जवाब देने की कोशिश में बहुत सारे इफ्स और बट्स हैं। यह आपके व्यू कंट्रोलर फ्लो पर निर्भर करता है। @ विलबर का उत्तर इसे ट्रेस करने के लिए एक अच्छा प्रारंभिक बिंदु होना चाहिए।
दीपक दंडुपोलु

ठीक है, चलो इसे एक विशिष्ट मामले में सरल करते हैं। अगर मैं UIAlertView का क्लोन लिखना चाहता था, तो मैं यह कैसे करूंगा? ध्यान दें कि यह अन्य नियंत्रकों या विचारों के लिए किसी भी पते पर पारित किए बिना ठीक काम कर सकता है।
हॉट लिक्स

4
@ डैनियल: चेतावनी के समान ओवरले को देखने के लिए एक दूसरा UIWindow अच्छी तरह से काम करता है।
विल्बर वंड्रस्मिथ

जवाबों:


75

iOS 4 ने UIWindow पर rootViewController संपत्ति पेश की:

[UIApplication sharedApplication].keyWindow.rootViewController;

हालाँकि, व्यू कंट्रोलर बनाने के बाद आपको इसे स्वयं सेट करना होगा।


155
विल्बर, यह आपको इसके विपरीत देगा जो ऑप ने मांगा था। rootViewController सबसे ऊपर के बजाय बेस व्यू कंट्रोलर है।
m4rkk

3
m4rkk: "टॉप-मोस्ट" इस बात पर निर्भर करता है कि आप किस दिशा से देख रहे हैं। क्या नए नियंत्रकों को शीर्ष (स्टैक-लाइक) या नीचे (ट्री-लाइक) में जोड़ा जाता है? किसी भी स्थिति में, ओपी ने नेविगेशन नियंत्रक को शीर्ष पर होने के रूप में उल्लेख किया है, जो बढ़ते-बढ़ते दृश्य को दर्शाता है।
विल्बर वंड्समिथ

50
शब्द that शीर्ष ”का उपयोग दृश्य नियंत्रक के लिए किया जाता है, जो कि शीर्ष पर दृश्यमान है (जैसे -[UINavigationController topViewController])। तब शब्द “जड़” है, जो कि पेड़ की जड़ है (जैसे -[UIWindow rootViewController]
Tricertops

13
@ImpurestClub मैं में में मिल नहीं पा रहा हूँ प्रलेखन , नहीं Xcode यह खोजने के लिए प्रतीत होता है।
Drux

4
@adib नहीं, यह UINavigationController का है
डेविड एच।

428

मुझे लगता है कि आपको स्वीकृत उत्तर और @ फिशस्टिक्स के संयोजन की आवश्यकता है

+ (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    return topController;
}

स्विफ्ट 3.0+

func topMostController() -> UIViewController? {
    guard let window = UIApplication.shared.keyWindow, let rootViewController = window.rootViewController else {
        return nil
    }

    var topController = rootViewController

    while let newTopController = topController.presentedViewController {
        topController = newTopController
    }

    return topController
}

4
इसके अलावा, आप जांच सकते हैं UINavigationControllerऔर इसके लिए पूछ सकते हैं topViewControllerया इसके लिए भी UITabBarControllerपूछ सकते हैं और पूछ सकते हैं selectedViewController। यह आपको दृश्य नियंत्रक मिलेगा जो वर्तमान में उपयोगकर्ता को दिखाई देता है।
ट्रिकर्टॉप्स

33
यह एक अधूरा समाधान है, क्योंकि यह केवल सामान्य रूप से प्रस्तुत दृश्य नियंत्रकों के पदानुक्रम का पता लगाता है, चाइल्डव्यूकंट्रोलर्स के पदानुक्रम का नहीं (जैसा कि UINavigationController, UITabBarontontroller, आदि द्वारा उपयोग किया जाता है)।
algal

3
यह मोडल व्यू कंट्रोलर को प्रस्तुत करने का एक बहुत अच्छा तरीका है जो वर्तमान एप्लिकेशन स्थिति के लिए फिर से शुरू होता है, मेरे मामले में यह एप्लिकेशन टाइम आउट होने के बाद पासवर्ड रीएंट्री स्क्रीन था। धन्यवाद!
erversteeg

11
@algal: वास्तव में नहीं: UITabBarController, UINavigationController हैं पहले से ही पदानुक्रम में सर्वोच्च दृश्य नियंत्रकों। आप "सर्वोच्च नियंत्रक" के साथ क्या करना चाहते हैं, इस पर निर्भर करते हुए, आप उन्हें बिल्कुल नहीं देखना चाहते हैं और उनकी सामग्री के साथ बेला कर सकते हैं। मेरे मामले में यह सब कुछ के शीर्ष पर एक मोडल कंट्रोलर प्रस्तुत करना था, और इसके लिए मुझे UINaviationController या UITabBarController प्राप्त करने की आवश्यकता है, उनकी सामग्री नहीं !!
रिक

1
@ Rick77, अगर यह सच है, तो आपकी एक छोटी सी टिप्पणी यहाँ दफन कर दी गई है जो अन्य उत्तरों में जटिल संशोधनों के टन को अनावश्यक रूप से प्रस्तुत करती है। चूँकि कोई और इसका उल्लेख नहीं करता है, इसलिए मुझे लगता है कि मुझे आपसे यह पुछना होगा कि यह सच है। और अगर यह है, तो यह इतना महत्वपूर्ण है कि यह अपने आप में एक जवाब होने के योग्य है। क्योंकि अन्य उत्तरों के बड़े बहुमत इस मुद्दे को संबोधित करने की कोशिश कर रहे हैं। आप जान बचा रहे होंगे!
ले मोट जूस

150

जोनासजी के उत्तर को पूरा करने के लिए (जिन्होंने ट्रैवर्स करते समय टैब बार कंट्रोलर को छोड़ दिया), यहां वर्तमान में दिए गए व्यू एक्सपर्ट्स को वापस करने का मेरा संस्करण है:

- (UIViewController*)topViewController {
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

2
अच्छा, हाँ मैं TabBar नियंत्रकों के बारे में भूल गया: पी
जोनास

9
शामिल नहीं हैchildViewControllers
भयानक-ओ

नीचे दिए गए मेरे उत्तर को देखें जो कि @kleo द्वारा छोड़े गए मामलों को संभालते हुए ऊपर दिए गए उत्तर में सुधार करता है, जैसे कि पॉपओवर, व्यू कंट्रोलर ट्रैवर्सिंग करते समय कुछ अन्य दृश्य नियंत्रकों के लिए साक्षात्कार के रूप में जोड़े गए
राजेश

यदि आप रिटर्न का उपयोग कर रहे हैं [self topViewControllerWithRootViewController: navigationController.vanishViewController] ;, तो दृश्य व्यू कंट्रोलर स्वयं प्रस्तुत व्यू कंट्रोलर (यदि कोई हो) लौटाता है, भले ही वह UIAlertController हो। ऐसे किसी व्यक्ति के लिए जिसे ui अलर्ट कंट्रोलर से बचना है, दृश्य व्यू कॉन्ट्रोलर के बजाय topViewController का उपयोग करें
Johnykutty

बस इसमें अपना 50 प्रतिशत जोड़ने के लिए - मैं अपने व्यू कॉन्ट्रॉलर में इस काम को पाने के लिए संघर्ष कर रहा था जो कि एक वेब व्यू को लोड करता है .. जिस कारण से मुझे यह काम नहीं मिल पाया क्योंकि दृश्य अभी भी तैयार नहीं था (लोडिंग समाप्त नहीं हुई) और इसलिए यह दिखाई नहीं दे रहा था। यह एक ऐसी स्थिति का कारण बन गया जहां एक TopViewContoller प्राप्त करना विफल हो रहा था, क्योंकि UINavigationController एक दृश्य ViewController प्राप्त करने की कोशिश कर रहा था, जबकि अभी तक कोई दृश्य दृश्य नियंत्रक नहीं था। तो अगर किसी को भी इस समस्या का सामना करना पड़ता है, तो सुनिश्चित करें कि ऊपर दिए गए TopViewController तरीके से कॉल करने से पहले आपका दृश्य लोड हो रहा है।
मबस्टर

52

एक पूर्ण गैर-पुनरावर्ती संस्करण, विभिन्न परिदृश्यों की देखभाल:

  • व्यू कंट्रोलर एक और दृश्य प्रस्तुत कर रहा है
  • व्यू कंट्रोलर ए है UINavigationController
  • व्यू कंट्रोलर ए है UITabBarController

उद्देश्य सी

 UIViewController *topViewController = self.window.rootViewController;
 while (true)
 {
     if (topViewController.presentedViewController) {
         topViewController = topViewController.presentedViewController;
     } else if ([topViewController isKindOfClass:[UINavigationController class]]) {
         UINavigationController *nav = (UINavigationController *)topViewController;
         topViewController = nav.topViewController;
     } else if ([topViewController isKindOfClass:[UITabBarController class]]) {
         UITabBarController *tab = (UITabBarController *)topViewController;
         topViewController = tab.selectedViewController;
     } else {
         break;
     }
 }

स्विफ्ट 4+

extension UIWindow {
    func topViewController() -> UIViewController? {
        var top = self.rootViewController
        while true {
            if let presented = top?.presentedViewController {
                top = presented
            } else if let nav = top as? UINavigationController {
                top = nav.visibleViewController
            } else if let tab = top as? UITabBarController {
                top = tab.selectedViewController
            } else {
                break
            }
        }
        return top
    }
}

2
मैंने visibleViewControllerइसे स्पष्ट करने के लिए इसका नाम दिया कि यह क्या करता है।
जॉनी

31

एक्सटेंशन का उपयोग करके स्विफ्ट के लिए शीर्ष सबसे अधिक दृश्य नियंत्रक प्राप्त करना

कोड:

extension UIViewController {
    @objc func topMostViewController() -> UIViewController {
        // Handling Modal views
        if let presentedViewController = self.presentedViewController {
            return presentedViewController.topMostViewController()
        }
        // Handling UIViewController's added as subviews to some other views.
        else {
            for view in self.view.subviews
            {
                // Key property which most of us are unaware of / rarely use.
                if let subViewController = view.next {
                    if subViewController is UIViewController {
                        let viewController = subViewController as! UIViewController
                        return viewController.topMostViewController()
                    }
                }
            }
            return self
        }
    }
}

extension UITabBarController {
    override func topMostViewController() -> UIViewController {
        return self.selectedViewController!.topMostViewController()
    }
}

extension UINavigationController {
    override func topMostViewController() -> UIViewController {
        return self.visibleViewController!.topMostViewController()
    }
}

उपयोग:

UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController()

उत्कृष्ट - इस समाधान के लिए बहुत बहुत धन्यवाद। उप-साक्षात्कार की जरूरत नहीं थी! फिर से, बहुत धन्यवाद, आपने मेरा दिन बचाया।
आईकेके

25

एरिक के जवाब को पूरा करने के लिए (जो पॉपओवर, नेविगेशन कंट्रोलर, टैबबार कॉन्ट्रोलर, व्यू कंट्रोलर को ट्रैवर्सिंग करते समय कुछ अन्य व्यू कंट्रोलर के साथ साक्षात्कार के रूप में जोड़ा गया) को पूरा करने के लिए, यहां वर्तमान में दिखाई देने वाले दृश्य नियंत्रक को वापस करने का मेरा संस्करण है:

================================================== ===================

- (UIViewController*)topViewController {
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)viewController {
    if ([viewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)viewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([viewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navContObj = (UINavigationController*)viewController;
        return [self topViewControllerWithRootViewController:navContObj.visibleViewController];
    } else if (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) {
        UIViewController* presentedViewController = viewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    }
    else {
        for (UIView *view in [viewController.view subviews])
        {
            id subViewController = [view nextResponder];
            if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
            {
                if ([(UIViewController *)subViewController presentedViewController]  && ![subViewController presentedViewController].isBeingDismissed) {
                    return [self topViewControllerWithRootViewController:[(UIViewController *)subViewController presentedViewController]];
                }
            }
        }
        return viewController;
    }
}

================================================== ===================

और अब आप सभी को शीर्ष सबसे अधिक देखने के लिए नियंत्रक की आवश्यकता है, उपरोक्त विधि को इस प्रकार कहें:

UIViewController *topMostViewControllerObj = [self topViewController];

स्प्लिट्स व्यू कॉन्ट्रोलर भी गुम है?
अपिनहो

21

इस उत्तर में childViewControllersस्वच्छ और पठनीय कार्यान्वयन शामिल है और इसे बनाए रखता है।

+ (UIViewController *)topViewController
{
    UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

    return [rootViewController topVisibleViewController];
}

- (UIViewController *)topVisibleViewController
{
    if ([self isKindOfClass:[UITabBarController class]])
    {
        UITabBarController *tabBarController = (UITabBarController *)self;
        return [tabBarController.selectedViewController topVisibleViewController];
    }
    else if ([self isKindOfClass:[UINavigationController class]])
    {
        UINavigationController *navigationController = (UINavigationController *)self;
        return [navigationController.visibleViewController topVisibleViewController];
    }
    else if (self.presentedViewController)
    {
        return [self.presentedViewController topVisibleViewController];
    }
    else if (self.childViewControllers.count > 0)
    {
        return [self.childViewControllers.lastObject topVisibleViewController];
    }

    return self;
}

कुछ कोड अपडेट किए गए, कारण भी बताएं कि इसे कम से कम करने और इसे फिर से बहाल करने से क्या नियंत्रक है। nik-kov-ios-developer.blogspot.ru/2016/12/…
निक कोव

अरे, चलिए, आपका "TopVanishViewController" कहाँ है?
स्वर्ग

12

मुझे हाल ही में अपनी एक परियोजना में यह स्थिति मिली, जो कि नियंत्रक द्वारा प्रदर्शित की जाने वाली सूचना को प्रदर्शित करने के लिए आवश्यक था जो कुछ भी प्रदर्शित किया गया था और जो कुछ भी प्रकार (UINavigationController, क्लासिक नियंत्रक या कस्टम दृश्य नियंत्रक) था, जब नेटवर्क की स्थिति बदल गई।

इसलिए मैंने अपना कोड जारी किया, जो कि काफी आसान है और वास्तव में एक प्रोटोकॉल पर आधारित है ताकि यह हर प्रकार के कंटेनर नियंत्रक के साथ लचीला हो। यह अंतिम उत्तरों से संबंधित है, लेकिन बहुत लचीले तरीके से लगता है।

आप यहाँ कोड को पकड़ सकते हैं: PPTopMostController

और सबसे अधिक नियंत्रक का उपयोग करके प्राप्त किया

UIViewController *c = [UIViewController topMostController];

10

यह एरिक के जवाब में सुधार है:

UIViewController *_topMostController(UIViewController *cont) {
    UIViewController *topController = cont;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    if ([topController isKindOfClass:[UINavigationController class]]) {
        UIViewController *visible = ((UINavigationController *)topController).visibleViewController;
        if (visible) {
            topController = visible;
        }
    }

    return (topController != cont ? topController : nil);
}

UIViewController *topMostController() {
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    UIViewController *next = nil;

    while ((next = _topMostController(topController)) != nil) {
        topController = next;
    }

    return topController;
}

_topMostController(UIViewController *cont) एक सहायक कार्य है।

अब आपको बस कॉल करने की जरूरत है topMostController()और सबसे ऊपर के UIViewController को लौटा दिया जाना चाहिए!


7
1983 से मैं कहूंगा। याद रखें कि ऑब्जेक्टिव-सी में सी होता है ... सी फंक्शन्स में ओब्जेकिंग ओबीसी कोड लपेटना एक आम बात है, इसलिए, यह ऑब्जेक्टिव-सी कोड है।
जोनास 5

@ जॉनसन हाय जोनास, किन परिस्थितियों में आप सी में ओबजेक कोड को लपेटना पसंद करते हैं? क्योंकि, मैं कभी-कभी C फ़ंक्शन को इस तरह देखता हूं और उपयोग को अलग नहीं कर सकता। C में रैपिंग कोड क्या कोई प्रदर्शन लाभ प्रदान करता है?
ओजबोज

1
@OzBoz उन स्थितियों में जहां यह तुरंत स्पष्ट नहीं है कि किस वर्ग selfसे संबंधित होना चाहिए।
adib

8

यहाँ मेरा इस पर ले रहा है। UIAlertView को सबसे शीर्ष नियंत्रक के रूप में प्राप्त करने के तरीके को इंगित करने के लिए @Stakenborg के लिए धन्यवाद

-(UIWindow *) returnWindowWithWindowLevelNormal
{
    NSArray *windows = [UIApplication sharedApplication].windows;
    for(UIWindow *topWindow in windows)
    {
        if (topWindow.windowLevel == UIWindowLevelNormal)
            return topWindow;
    }
    return [UIApplication sharedApplication].keyWindow;
}

-(UIViewController *) getTopMostController
{
    UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
    if (topWindow.windowLevel != UIWindowLevelNormal)
    {
        topWindow = [self returnWindowWithWindowLevelNormal];
    }

    UIViewController *topController = topWindow.rootViewController;
    if(topController == nil)
    {
        topWindow = [UIApplication sharedApplication].delegate.window;
        if (topWindow.windowLevel != UIWindowLevelNormal)
        {
            topWindow = [self returnWindowWithWindowLevelNormal];
        }
        topController = topWindow.rootViewController;
    }

    while(topController.presentedViewController)
    {
        topController = topController.presentedViewController;
    }

    if([topController isKindOfClass:[UINavigationController class]])
    {
        UINavigationController *nav = (UINavigationController*)topController;
        topController = [nav.viewControllers lastObject];

        while(topController.presentedViewController)
        {
            topController = topController.presentedViewController;
        }
    }

    return topController;
}

आपको getSomething:उद्देश्य-सी में नामकरण विधियों से बचना चाहिए । इसका एक विशेष अर्थ है (अधिक: cocoadevcentral.com/articles/000082.php ) और आप अपने कोड में इन आवश्यकताओं को पूरा नहीं करते हैं।
Vive

7
@ कार्यान्वयन UIWindow (एक्सटेंशन)

- (UIViewController *) topMostController
{
    UIViewController * topController = [स्वयं rootViewController];

    जबकि (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    टॉपकंट्रोलर वापस;
}

@समाप्त

मुझे नहीं लगता कि आप मूल पोस्ट में बताई गई शर्त से संतुष्ट हैं।
हॉट लिप्स 23

7
- (UIViewController*)topViewController {
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

मैंने इसका इस्तेमाल किया, लेकिन ध्यान दें कि यह तब टूटता है जब एक से अधिक प्रस्तुत दृश्य नियंत्रक
चक बोरिस

7

नवीनतम स्विफ्ट संस्करण के लिए:
एक फ़ाइल बनाएं, इसे नाम दें UIWindowExtension.swiftऔर निम्नलिखित स्निपेट पेस्ट करें:

import UIKit

public extension UIWindow {
    public var visibleViewController: UIViewController? {
        return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
    }

    public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
        if let nc = vc as? UINavigationController {
            return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
        } else if let tc = vc as? UITabBarController {
            return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
        } else {
            if let pvc = vc?.presentedViewController {
                return UIWindow.getVisibleViewControllerFrom(pvc)
            } else {
                return vc
            }
        }
    }
}

func getTopViewController() -> UIViewController? {
    let appDelegate = UIApplication.sharedApplication().delegate
    if let window = appDelegate!.window {
        return window?.visibleViewController
    }
    return nil
}

इसे कहीं भी उपयोग करें:

if let topVC = getTopViewController() {

}

मैं आपका उत्तर बहुत अधिक नहीं बदलना चाहता, लेकिन कुछ बातों का सुझाव दूंगा। 1. UISplitViewController के लिए समर्थन जोड़ें। 2. switchयदि इसके बजाय का उपयोग करें । 3. सुनिश्चित नहीं है कि आपको एक स्थिर फ़ंक्शन की आवश्यकता है, मुझे लगता है कि आप इसे पहली बार आपके द्वारा घोषित किए गए प्रथम स्तर के संस्करण में आसानी से कर सकते हैं। 4. शायद बहुत सारे वैश्विक कार्यों को बनाने के लिए सबसे अच्छा नहीं है, लेकिन यह स्वाद का मामला है। वैश्विक फ़ंक्शन के प्रभाव को प्राप्त करने के लिए आप कोड की एक पंक्ति का उपयोग कर सकते हैं:UIApplication.sharedApplication().delegate?.window?.visibleViewController
जॉर्डन स्मिथ

7

UIApplicationस्विफ्ट में सरल विस्तार :

ध्यान दें:

यह moreNavigationControllerभीतर की परवाह करता हैUITabBarController

extension UIApplication {

    class func topViewController(baseViewController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {

        if let navigationController = baseViewController as? UINavigationController {
            return topViewController(navigationController.visibleViewController)
        }

        if let tabBarViewController = baseViewController as? UITabBarController {

            let moreNavigationController = tabBarViewController.moreNavigationController

            if let topViewController = moreNavigationController.topViewController where topViewController.view.window != nil {
                return topViewController(topViewController)
            } else if let selectedViewController = tabBarViewController.selectedViewController {
                return topViewController(selectedViewController)
            }
        }

        if let splitViewController = baseViewController as? UISplitViewController where splitViewController.viewControllers.count == 1 {
            return topViewController(splitViewController.viewControllers[0])
        }

        if let presentedViewController = baseViewController?.presentedViewController {
            return topViewController(presentedViewController)
        }

        return baseViewController
    }
}

सरल उपयोग:

if let topViewController = UIApplication.topViewController() {
    //do sth with top view controller
}

YES YES YES - topMostViewController खोजने के लिए वेब के आसपास कई समाधान हैं, लेकिन यदि आप ऐप में अधिक टैब के साथ टैब बार हैं, तो आप इसे थोड़ा अलग संभाल लेंगे।
एंडी ओब्यूसेक

7

वर्तमान दृश्यमान को हथियाने के लिए नीचे दिए गए एक्सटेंशन का उपयोग करें UIViewController। स्विफ्ट 4.0 और बाद के लिए काम किया

स्विफ्ट 4.0 और बाद में:

extension UIApplication {
    
    class func topViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = viewController as? UINavigationController {
            return topViewController(nav.visibleViewController)
        }
        if let tab = viewController as? UITabBarController {
            if let selected = tab.selectedViewController {
                return topViewController(selected)
            }
        }
        if let presented = viewController?.presentedViewController {
            return topViewController(presented)
        }
        return viewController
    }
}

कैसे इस्तेमाल करे?

let objViewcontroller = UIApplication.topViewController()

presentedViewControllerपहले UINavigationControllerऔर UITabBarControllerमामलों के लिए यह परीक्षण नहीं होना चाहिए ? अन्यथा, यदि कोई व्यू कंट्रोलर मामूली रूप से प्रस्तुत किया जाता है UINavigationControllerया UITabBarControllerइसे शीर्ष दृश्य नियंत्रक के रूप में वापस नहीं किया जाएगा, भले ही यह दृश्य नियंत्रक है जो दिखाई दे रहा है।
ड्रयू

4

फिर भी एक और स्विफ्ट समाधान

func topController() -> UIViewController? {

    // recursive follow
    func follow(from:UIViewController?) -> UIViewController? {
        if let to = (from as? UITabBarController)?.selectedViewController {
            return follow(to)
        } else if let to = (from as? UINavigationController)?.visibleViewController {
            return follow(to)
        } else if let to = from?.presentedViewController {
            return follow(to)
        }
        return from
    }

    let root = UIApplication.sharedApplication().keyWindow?.rootViewController

    return follow(root)

}

4

स्विफ्ट 4.2 एक्सटेंशन


extension UIApplication {

    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {


            return topViewController(controller: presented)
        }
        return controller
    }
}

इसे कहीं से भी उपयोग करें,

 UIApplication.topViewController()?.present(yourController, animated: true, completion: nil)

या पसंद है,

 UIApplication.topViewController()?
                    .navigationController?
                    .popToViewController(yourController,
                                         animated: true)

UINavigationController, UITabBarController जैसे किसी भी वर्ग के लिए फिट

का आनंद लें!


1
@ बिलाल बखरोम कहते हैं, "अपवोटेड। मुझे लगता है कि आपका जवाब सबसे अच्छा है। आप सीधे टॉप व्यू कॉंट्रोलर () विधि को कॉल नहीं कर सकते। अपाइलेशन क्लास सिंगलटन है," साझा "नामक एक उदाहरण का उपयोग करें।" में एक संपादन मैं अस्वीकार करने के लिए मतदान किया है कि। यदि यह वास्तव में सही है, तो कृपया उस मेनू पर ले जाएं जहां आप उस संपादन को अनुमोदित कर सकते हैं।
wizzwizz4

3

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

मैंने पाया कि कभी-कभी कंट्रोलर की विंडो पर शून्य होता है, क्योंकि कीविन्डो कुछ ओएस चीज जैसे अलर्ट, आदि है।

 + (UIViewController*)topMostController
 {
     UIWindow *topWndow = [UIApplication sharedApplication].keyWindow;
     UIViewController *topController = topWndow.rootViewController;

     if (topController == nil)
     {
         // The windows in the array are ordered from back to front by window level; thus,
         // the last window in the array is on top of all other app windows.
         for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator])
         {
             topController = aWndow.rootViewController;
             if (topController)
                 break;
         }
     }

     while (topController.presentedViewController) {
         topController = topController.presentedViewController;
     }

     return topController;
 }

3

@ एरिक के जवाब पर विस्तार करते हुए, आपको सावधान रहने की जरूरत है कि कीवॉन्ड वास्तव में वह विंडो है जिसे आप चाहते हैं। यदि आप उदाहरण के लिए किसी अलर्ट दृश्य में कुछ टैप करने के बाद इस पद्धति का उपयोग करने का प्रयास कर रहे हैं, तो कीवॉन्ड वास्तव में अलर्ट की विंडो होगी, और इससे आपके लिए कोई संदेह नहीं होगा। यह मेरे साथ जंगल में हुआ जब एक अलर्ट के माध्यम से गहरे लिंक को संभालना और NO STACK TRACE वाले SIGABRTs का कारण बना। डिबग करने के लिए कुल कुतिया।

अब मैं जिस कोड का उपयोग कर रहा हूं:

- (UIViewController *)getTopMostViewController {
    UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
    if (topWindow.windowLevel != UIWindowLevelNormal) {
        NSArray *windows = [UIApplication sharedApplication].windows;
        for(topWindow in windows)
        {
            if (topWindow.windowLevel == UIWindowLevelNormal)
                break;
        }
    }

    UIViewController *topViewController = topWindow.rootViewController;

    while (topViewController.presentedViewController) {
        topViewController = topViewController.presentedViewController;
    }

    return topViewController;
}

इस प्रश्न पर अन्य उत्तरों से आप जिस शीर्ष दृश्य नियंत्रक को प्राप्त करना चाहते हैं, उसके स्वाद के साथ इसे बेझिझक मिलाएं।


क्या आपने इसे पूर्ण समाधान माना है? इतने सारे अन्य जवाब बेहद जटिल हैं, इतने सारे किनारे के मामलों को ध्यान में रखते हुए। मैं चाहता हूं कि यह सच हो, यह इतना सरल और सुरुचिपूर्ण है।
ले मोट जूस

मुझे इससे कोई समस्या नहीं है। यदि आप अपने नेवी स्टैक के साथ कुछ भी असामान्य नहीं कर रहे हैं तो यह काम करना चाहिए, अन्यथा कुछ अन्य समाधान अधिक जटिल मामलों को संभालते हैं।
स्टेकनबॉर्ग

3

वैकल्पिक स्विफ्ट समाधान:

static func topMostController() -> UIViewController {
    var topController = UIApplication.sharedApplication().keyWindow?.rootViewController
    while (topController?.presentedViewController != nil) {
        topController = topController?.presentedViewController
    }

    return topController!
}

3

यह समाधान सबसे पूर्ण है। यह ध्यान में रखता है: UINavigationController UIPageViewController UITabBarController और शीर्ष दृश्य नियंत्रक से सबसे ऊपर प्रस्तुत दृश्य नियंत्रक

इसका उदाहरण स्विफ्ट 3 में है।

3 ओवरलोड हैं

//Get the topmost view controller for the current application.
public func MGGetTopMostViewController() -> UIViewController?  {

    if let currentWindow:UIWindow = UIApplication.shared.keyWindow {
        return MGGetTopMostViewController(fromWindow: currentWindow)
    }

    return nil
}

//Gets the topmost view controller from a specific window.
public func MGGetTopMostViewController(fromWindow window:UIWindow) -> UIViewController? {

    if let rootViewController:UIViewController = window.rootViewController
    {
        return MGGetTopMostViewController(fromViewController:  rootViewController)
    }

    return nil
}


//Gets the topmost view controller starting from a specific UIViewController
//Pass the rootViewController into this to get the apps top most view controller
public func MGGetTopMostViewController(fromViewController viewController:UIViewController) -> UIViewController {

    //UINavigationController
    if let navigationViewController:UINavigationController = viewController as? UINavigationController {
        let viewControllers:[UIViewController] = navigationViewController.viewControllers
        if navigationViewController.viewControllers.count >= 1 {
            return MGGetTopMostViewController(fromViewController: viewControllers[viewControllers.count - 1])
        }
    }

    //UIPageViewController
    if let pageViewController:UIPageViewController = viewController as? UIPageViewController {
        if let viewControllers:[UIViewController] = pageViewController.viewControllers {
            if viewControllers.count >= 1 {
                return MGGetTopMostViewController(fromViewController: viewControllers[0])
            }
        }
    }

    //UITabViewController
    if let tabBarController:UITabBarController = viewController as? UITabBarController {
        if let selectedViewController:UIViewController = tabBarController.selectedViewController {
            return MGGetTopMostViewController(fromViewController: selectedViewController)
        }
    }

    //Lastly, Attempt to get the topmost presented view controller
    var presentedViewController:UIViewController! = viewController.presentedViewController
    var nextPresentedViewController:UIViewController! = presentedViewController?.presentedViewController

    //If there is a presented view controller, get the top most prensentedViewController and return it.
    if presentedViewController != nil {
        while nextPresentedViewController != nil {

            //Set the presented view controller as the next one.
            presentedViewController = nextPresentedViewController

            //Attempt to get the next presented view controller
            nextPresentedViewController = presentedViewController.presentedViewController
        }
        return presentedViewController
    }

    //If there is no topmost presented view controller, return the view controller itself.
    return viewController
}

3

स्विफ्ट 4.2 में एक संक्षिप्त रूप से व्यापक समाधान , यूनीवीगेशन कॉन्ट्रोलर्स , यूआईटैबरकंट्रोलर्स , प्रस्तुत और चाइल्ड व्यू कंट्रोलर्स को ध्यान में रखता है :

extension UIViewController {
  func topmostViewController() -> UIViewController {
    if let navigationVC = self as? UINavigationController,
      let topVC = navigationVC.topViewController {
      return topVC.topmostViewController()
    }
    if let tabBarVC = self as? UITabBarController,
      let selectedVC = tabBarVC.selectedViewController {
      return selectedVC.topmostViewController()
    }
    if let presentedVC = presentedViewController {
      return presentedVC.topmostViewController()
    }
    if let childVC = children.last {
      return childVC.topmostViewController()
    }
    return self
  }
}

extension UIApplication {
  func topmostViewController() -> UIViewController? {
    return keyWindow?.rootViewController?.topmostViewController()
  }
}

उपयोग:

let viewController = UIApplication.shared.topmostViewController()

2

स्विफ्ट में शानदार समाधान, ऐपडेलगेट में लागू

func getTopViewController()->UIViewController{
    return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{
    if rootViewController is UITabBarController{
        let tabBarController = rootViewController as! UITabBarController
        return topViewControllerWithRootViewController(tabBarController.selectedViewController!)
    }
    if rootViewController is UINavigationController{
        let navBarController = rootViewController as! UINavigationController
        return topViewControllerWithRootViewController(navBarController.visibleViewController)
    }
    if let presentedViewController = rootViewController.presentedViewController {
        return topViewControllerWithRootViewController(presentedViewController)
    }
    return rootViewController
}

1

मुझे लगता है कि अधिकांश उत्तर पूरी तरह से नजरअंदाज कर दिए गए हैं UINavigationViewController, इसलिए मैंने निम्नलिखित कार्यान्वयन के साथ इस उपयोग के मामले को संभाला।

+ (UIViewController *)topMostController {
    UIViewController * topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (topController.presentedViewController || [topController isMemberOfClass:[UINavigationController class]]) {
        if([topController isMemberOfClass:[UINavigationController class]]) {
            topController = [topController childViewControllers].lastObject;
        } else {
            topController = topController.presentedViewController;
        }
    }

    return topController;
}

1

मुझे पता है कि यह बहुत देर से और बेमानी हो सकता है। लेकिन निम्नलिखित स्निपेट मेरे साथ आया है जो मेरे लिए काम कर रहा है:

    static func topViewController() -> UIViewController? {
        return topViewController(vc: UIApplication.shared.keyWindow?.rootViewController)
    }

    private static func topViewController(vc:UIViewController?) -> UIViewController? {
        if let rootVC = vc {
            guard let presentedVC = rootVC.presentedViewController else {
                return rootVC
            }
            if let presentedNavVC = presentedVC as? UINavigationController {
                let lastVC = presentedNavVC.viewControllers.last
                return topViewController(vc: lastVC)
            }
            return topViewController(vc: presentedVC)
        }
        return nil
    }

0

यह किसी भी मूल दृश्य नियंत्रण से शीर्ष viewController 1 खोजने के लिए महान काम करता है

+ (UIViewController *)topViewControllerFor:(UIViewController *)viewController
{
    if(!viewController.presentedViewController)
        return viewController;
    return [MF5AppDelegate topViewControllerFor:viewController.presentedViewController];
}

/* View Controller for Visible View */

AppDelegate *app = [UIApplication sharedApplication].delegate;
UIViewController *visibleViewController = [AppDelegate topViewControllerFor:app.window.rootViewController]; 

0

निश्चित नहीं है कि यह क्या आप शीर्ष दृश्य नियंत्रक को खोजने के द्वारा पूरा करने की कोशिश कर रहे हैं, लेकिन मैं एक नया दृश्य नियंत्रक पेश करने की कोशिश कर रहा था, लेकिन अगर मेरे रूट दृश्य नियंत्रक में पहले से ही एक मामूली संवाद था, तो इसे अवरुद्ध कर दिया जाएगा, इसलिए मैं इस कोड का उपयोग करके सभी मोडल व्यू कंट्रोलर के शीर्ष पर चक्र होगा:

UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController;

while( parentController.presentedViewController &&
       parentController != parentController.presentedViewController )
{
    parentController = parentController.presentedViewController;
}

0

आप का उपयोग करके शीर्ष सर्वाधिक दृश्य नियंत्रक पा सकते हैं

NSArray *arrViewControllers=[[self navigationController] viewControllers];
UIViewController *topMostViewController=(UIViewController *)[arrViewControllers objectAtIndex:[arrViewControllers count]-1];

इसके अलावा, यदि आप वास्तव में प्रश्न पढ़ते हैं, तो selfकोई navigationControllerसंपत्ति नहीं है।
हॉट लिक्स

0

एक अन्य समाधान उत्तरदाता श्रृंखला पर निर्भर करता है, जो पहले उत्तरदाता के आधार पर काम कर सकता है या नहीं कर सकता है:

  1. पहला प्रत्युत्तर प्राप्त करें
  2. उस पहले उत्तरदाता के साथ संबद्ध UIViewController प्राप्त करें

उदाहरण छद्म कोड:

+ (UIViewController *)currentViewController {
    UIView *firstResponder = [self firstResponder]; // from the first link above, but not guaranteed to return a UIView, so this should be handled more appropriately.
    UIViewController *viewController = [firstResponder viewController]; // from the second link above
    return viewController;
}

0

स्विफ्ट:

extension UIWindow {

func visibleViewController() -> UIViewController? {
    if let rootViewController: UIViewController  = self.rootViewController {
        return UIWindow.getVisibleViewControllerFrom(rootViewController)
    }
    return nil
}

class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKindOfClass(UINavigationController.self) {

    let navigationController = vc as UINavigationController
    return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)

} else if vc.isKindOfClass(UITabBarController.self) {

    let tabBarController = vc as UITabBarController
    return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)

} else {

    if let presentedViewController = vc.presentedViewController {

        return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)

    } else {

        return vc;
    }
}
}

उपयोग:

 if let topController = window.visibleViewController() {
            println(topController)
        }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.