"व्यू कंट्रोलर से" UIViewControllerContextTransitioning का उपयोग करके गायब हो जाता है


105

मुझे एक समस्या मिली और मैंने इसे नीचे वर्णित किया है।

मैं UIViewControllerContextTransitioningकस्टम बदलाव के लिए उपयोग कर रहा हूं ।

मेरे पास 2 व्यू कंट्रोलर हैं, पहला व्यू कंट्रोलर और दूसरा व्यू कंट्रोलर।

अब मैं एक एनीमेशन के साथ पहले दृश्य नियंत्रक पर दूसरा दृश्य नियंत्रक जोड़ना चाहता हूं। मैंने इसे प्राप्त कर लिया है, अब दूसरा दृश्य नियंत्रक पारदर्शी है, इसलिए हम दूसरे दृश्य नियंत्रक के नीचे पहला दृश्य नियंत्रक देख सकते हैं।

लेकिन मैं पहले दृश्य नियंत्रक को देखने में सक्षम नहीं हूं, और मैं दूसरे दृश्य नियंत्रक के नीचे केवल काली स्क्रीन देख सकता हूं।

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    self.transitionContext = transitionContext;
    if(self.isPresenting){
        [self executePresentationAnimation:transitionContext];
    }
    else{
       [self executeDismissalAnimation:transitionContext];
    }
  }

-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
     UIView* inView = [transitionContext containerView];
     UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

     UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

     CGRect offScreenFrame = inView.frame;
     offScreenFrame.origin.y = inView.frame.size.height;
     toViewController.view.frame = offScreenFrame;

    toViewController.view.backgroundColor = [UIColor clearColor];
    fromViewController.view.backgroundColor = [UIColor clearColor];
    inView.backgroundColor = [UIColor  clearColor];
    [inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
     // [inView addSubview:toViewController.view];
    CFTimeInterval duration = self.presentationDuration;
    CFTimeInterval halfDuration = duration/2;

    CATransform3D t1 = [self firstTransform];
    CATransform3D t2 = [self secondTransformWithView:fromViewController.view];

    [UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{

    [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t1;
    }];

    [UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t2;
    }];
    } completion:^(BOOL finished) {
    }];


    [UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
        toViewController.view.frame = inView.frame;
    } completion:^(BOOL finished) {
        [self.transitionContext completeTransition:YES];
    }];
}

जब [self.transitionContext completeTransition:YES];कहा जाता है, तो अचानक पहला दृश्य नियंत्रक गायब हो जाता है और दूसरी स्क्रीन नियंत्रक के नीचे काली स्क्रीन प्रदर्शित होती है।

किसी एक विचार है? धन्यवाद।

जवाबों:


98

मैं यहाँ एक ही समस्या थी - iOS 8 में एक बग की तरह लग रहा है। मैं एक रडार दायर किया है

मैंने स्क्रीन के काले होने के बाद दृश्य पदानुक्रम का निरीक्षण करने के लिए Reveal का उपयोग किया । कुंजी UIWindowपूरी तरह से खाली है - कोई दृश्य पदानुक्रम बिल्कुल नहीं!

Reveal'd

मैं लगभग थोड़ा खेला और ऐसा लगता है कि सरल मामलों के लिए एक आसान समाधान है। आप बस toViewControllerमुख्य विंडो के उप के रूप में दृश्य को फिर से जोड़ सकते हैं:

transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)

मैंने जाँच की है और कुंजी विंडो rootViewControllerअभी भी सही ढंग से सेट है, इसलिए यह ठीक है। मुझे यकीन नहीं है कि अगर आप अपने नियंत्रक को पहले से ही प्रस्तुत किए गए मॉडल नियंत्रक से प्रस्तुत करते हैं, तो अधिक जटिल मामलों के लिए, आपको प्रयोग करना होगा।


2
मैंने इस मुद्दे को भी देखा है। iOS 8 fromView और toView तक पहुँचने के लिए एक नई विधि और कुंजियों का परिचय देता है (नोट: देखें नियंत्रक नहीं) ऐसा प्रतीत होता है जैसे कि ये संदर्भ संक्रमण के दौरान खो नहीं गए हैं। आप उन्हें कंटेनर दृश्य में जोड़ सकते हैं जैसा कि आप सामान्य रूप से करते हैं यदि आपने उन्हें केवल दृश्य नियंत्रकों से पुनर्प्राप्त किया था।
तपती

1
जब मैं अपने नेविगेशन कंट्रोलर के व्यू, व्यूडालैड में सब-कुछ जोड़ने की कोशिश कर रहा था, तो मुझे ऐसा ही iOS 8 अजीब दिख रहा था। कीविन्डो के लिए नेविगेशनकंट्रोलर के दृष्टिकोण को फिर से जोड़ना चाल को करने के लिए लग रहा था, बहुत बहुत धन्यवाद, ऐश!
टेबुल

1
मैं अभी भी जीएम में देख रहा हूं (और यह फिक्स अभी भी काम करता है)। क्या दूसरे भी वही देख रहे हैं? क्या यह सिर्फ एपीआई में बदलाव है?
rjkaplan

21
मैंने पाया कि यह बग (और भी कई!) सेट होने पर गायब हो जाता है modalPresentationStyle = UIModalPresentationFullScreen। आप निश्चित रूप से अभी भी अपने कस्टम संक्रमण एनीमेशन प्राप्त करते हैं।
क्रिस

1
धन्यवाद @AshFurrow जब तक इसे ठीक नहीं किया जाता है तब तक यह अच्छा है!
कंदेलविजय

78

मुझे लगता है कि इसके पीछे के तर्क को बेहतर तरीके से समझाया जाना चाहिए।

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

IOS 7 में सिस्टम हमेशा व्यू कंट्रोलर्स के विचार लौटाता है, जो ट्रांजेक्शन के बाद अपने मूल स्थानों पर प्रस्तुति (प्रेजेंटिंग और प्रेजेंट) में शामिल हो जाते हैं। यह अब iOS 8 में कुछ प्रस्तुति शैलियों के लिए नहीं होता है।

नियम बहुत सरल है: एनिमेटर को केवल वर्तमान दृश्य नियंत्रक के दृश्य में हेरफेर करना चाहिए, यदि उस दृश्य नियंत्रक का दृश्य संक्रमण के अंत तक (दृश्य पदानुक्रम से हटा दिया गया) पूरी तरह से छिपा हुआ हो । दूसरे शब्दों में इसका मतलब है कि प्रारंभिक प्रस्तुति एनीमेशन के समाप्त होने के बाद केवल प्रस्तुत दृश्य नियंत्रक का दृश्य दिखाई देगा और वर्तमान दृश्य नियंत्रक का दृश्य नहीं होगा। उदाहरण के लिए, यदि आपने दृश्य नियंत्रक की दृश्यता को 50% पर सेट किया है और UIModalPresentationFullScreen का उपयोग करते हैं, तो आप प्रस्तुत किए गए दृश्य नियंत्रक के दृश्य को प्रस्तुत करने के नीचे नहीं देख पाएंगे, लेकिन यदि आप UIModalresresationationOverFullscreen का उपयोग करते हैं - तो आप (UIPresentationController की shouldRemovePresentersViewविधि निर्दिष्ट करने के लिए ज़िम्मेदार होंगे)।

एनिमेटर को हर समय प्रस्तुतकर्ता नियंत्रक के दृष्टिकोण में हेरफेर करने की अनुमति क्यों नहीं दी जाती है? सबसे पहले, यदि वर्तमान दृश्य नियंत्रक का दृश्य पूरी प्रस्तुति जीवन चक्र के दौरान एनीमेशन के समाप्त होने के बाद दिखाई देने वाला है, तो उसे इसे चेतन करने की कोई आवश्यकता नहीं है - यह सिर्फ वहीं रहता है जहां यह है। दूसरा, अगर उस व्यू कंट्रोलर का स्वामित्व प्रेजेंटेशन कंट्रोलर को ट्रांसफर हो जाता है, तो प्रेजेंटेशन कंट्रोलर को यह पता नहीं चलेगा कि ओरिएंटेशन में बदलाव होने पर उदाहरण के लिए जरूरत पड़ने पर कंट्रोलर के व्यू को लेआउट कैसे करें, लेकिन प्रेजेंटेशन व्यू कंट्रोलर का ओरिजिनल ओनर क्या करता है ।

आईओएस 8 में viewForKey:विधि को उन विचारों को प्राप्त करने के लिए पेश किया गया था जो एनिमेटर में हेरफेर करता है। सबसे पहले, यह वापस लौटने वाले नियम का पालन करने में मदद करता है जब भी एनिमेटर को दृश्य को नहीं छूना चाहिए। दूसरा, यह एनिमेटर के लिए एक अलग दृश्य को चेतन में लौटा सकता है । कल्पना कीजिए कि आप फार्म शीट के समान एक प्रस्तुति को लागू कर रहे हैं। इस मामले में आप प्रस्तुत दृश्य नियंत्रक के दृश्य के आसपास कुछ छाया या सजावट जोड़ना चाहेंगे। एनिमेटर उस सजावट को चेतन करेगा और प्रस्तुत दृश्य नियंत्रक का दृश्य सजावट का एक बच्चा होगा।

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

जब आप स्पष्ट रूप से इसे एनिमेटर के कंटेनर दृश्य के अंदर रख देते हैं, तो गायब हो रहे दृश्य नियंत्रक के दृश्य के साथ समस्या को ठीक करने के लिए आप कई चीजें कर सकते हैं :

  1. यदि वर्तमान दृश्य नियंत्रक के दृश्य को चेतन करने की आवश्यकता नहीं है, तो viewForKey:सीधे नियंत्रक के विचारों को देखने के लिए पहुंचने के बजाय चेतन को देखने के लिए उपयोग करें। viewForKey:शून्य या यहां तक ​​कि पूरी तरह से अलग विचार वापस कर सकते हैं।

  2. आप पेश दृश्य नियंत्रकों की दृष्टि चेतन चाहते हैं आप का उपयोग पर विचार करना चाहिए UIModalPresentationFullScreenशैली या का उपयोग जारी रखने UIModalPresentationCustomऔर साथ UIPresentationController की अपनी खुद की उपवर्ग लागू shouldRemovePresentersViewलौटने YES। वास्तव में, इस पद्धति का कार्यान्वयन आंतरिक प्रस्तुति नियंत्रकों के बीच मुख्य अंतर है, जो इस तथ्य से अलग UIModalPresentationFullScreenऔर UIModalPresentationCustomशैलियों से अलग है कि उत्तरार्द्ध आपको कस्टम प्रस्तुति नियंत्रकों का उपयोग करने की अनुमति देता है।

  3. अन्य सभी दुर्लभ मामलों में आपको सुझाए गए अन्य उत्तरों के अनुसार वर्तमान नियंत्रक के दृष्टिकोण को उसके मूल स्थान पर लौटना होगा।


2
क्योंकि यही कारण है कि सुपर अजीब है इस कोड पर निर्भर करता है viewControllerForKey:की viewरों केवल जब viewForKey:रिटर्न शून्य, और मैं अभी भी पड़ा मैन्युअल खिड़की करने के लिए इसे फिर से जोड़ सकते हैं। क्या आपके पास इस वर्कअराउंड के बिना काम करने वाले कोड का एक उदाहरण है?
ऐश फुरो

ठीक है, अगर viewForKey:रिटर्न शून्य है, तो सुनिश्चित करें कि आपको अपने एनिमेटर में इसे हटाने से वर्तमान दृश्य नियंत्रक के विंडो में फिर से जोड़ना होगा। यदि व्यूफ़ोरके वास्तविक दृश्य नियंत्रक के दृश्य को लौटाता है, तो उस दृश्य को स्थानांतरित करना सुरक्षित होता है क्योंकि प्रस्तुति जीवनचक्र समाप्त होने के बाद UIKit इसे वापस मूल स्थिति में ले जाएगा।
१:२० बजे १२

इस मुद्दे के पीछे के तर्क को समझाने के लिए धन्यवाद। आप बिल्कुल सही कह रहे है। दृश्य पदानुक्रम में दृश्य की स्थिति को स्थानांतरित किए बिना इसे स्पष्ट रूप से गायब कर देगा (iOS 8 पोस्ट करें, और मैं अभी iOS 10 के साथ काम कर रहा हूं!) स्पष्ट करने के लिए धन्यवाद।
क्ले एलिस

1
धन्यवाद आपका स्पष्टीकरण के लिए egdmitry कैसे आपको लगता है मैं लागू करना चाहिए है एक: जो एक और सवाल जो है उठाना प्रकट प्रस्तुति की तरह? उन बहुत आम में से एक जहां आजकल प्रस्तुत दृश्य आंशिक रूप से प्रस्तुत दृश्य को नीचे दिखाने के लिए स्लाइड करता है? इस परिदृश्य में प्रस्तुत और प्रस्तुत दोनों विचारों को ऑनस्क्रीन होना चाहिए और प्रस्तुत दृश्य एक एनिमेटेड है।
एंड्रिया

70

IOS 8 में, आपको व्यू कंट्रोलर्स viewForKey:की .viewसंपत्ति के बदले दिए गए विचारों में हेरफेर करना होगाviewControllerForKey: । यह बीटा दस्तावेज़ से विशेष रूप से स्पष्ट नहीं है, लेकिन यदि आप UIViewControllerTransitioning.h के स्रोत पर गौर करते हैं, तो आपको यह टिप्पणी ऊपर दिखाई देगी viewControllerForKey::

// Currently only two keys are defined by the
// system - UITransitionContextToViewControllerKey, and
// UITransitionContextFromViewControllerKey.
// Animators should not directly manipulate a view controller's views and should
// use viewForKey: to get views instead.
- (UIViewController *)viewControllerForKey:(NSString *)key;

इसलिए फ्रेम आदि का समायोजन करने के बजाय toViewController.view, वापसी मूल्य का उपयोग करें[transitionContext viewForKey:UITransitionContextToViewKey]

यदि आपके ऐप को iOS7 और / या Xcode 5 का समर्थन करने की आवश्यकता है, तो आप निम्न की तरह UIViewController पर एक सरल श्रेणी पद्धति का उपयोग कर सकते हैं:

- (UIView *)viewForTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        NSString *key = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey] == self ? UITransitionContextFromViewKey : UITransitionContextToViewKey;
        return [transitionContext viewForKey:key];
    } else {
        return self.view;
    }
#else
    return self.view;
#endif
}

फिर, अपने toViewControllerऔरfromViewController हमेशा की तरह, लेकिन उपयोग करके विचार प्राप्त करें[toViewController viewForTransitionContext:transitionContext]

संपादित करें: एक बग प्रतीत होता है, जहां से प्रस्तुत करने पर दृश्य नियंत्रक का दृश्य शून्य होता है viewForKey, जो आपको ऐसे मोडल बदलाव करने से रोकता है जो प्रस्तुत करने वाले दृश्य को सभी में चेतन करता है (जैसे कि स्लाइडिंग, या फ्लिप-क्षैतिज)। मैंने rdar पर iOS8 के लिए एक बग दर्ज किया: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 )। इसके अलावा http://github.com/bcherry/TransitionBug पर नमूना परियोजना देखें

संपादन 2: सुझाव के लिए ग्रेवी का धन्यवाद, UIModalPresentationFullScreen का उपयोग करके समस्या को हल करता है। शायद यह बग नहीं है। Apple का इरादा हो सकता है कि UIModalPresentationCustom केवल आने वाले मॉडल के दृश्य को संशोधित करता है। यदि आप आउटगोइंग दृश्य को संशोधित करना चाहते हैं, तो आपको नए दृश्य की पूर्ण स्क्रीन प्रस्तुति की गारंटी देने की आवश्यकता है? किसी भी स्थिति में, आपको viewForKeyऔर UIModalPresentationFullScreen का उपयोग करना चाहिए ।


2
ViewForKey बग मुझे पागल कर रहा था! - दाखिल करने के लिए धन्यवाद। FWIW मेरा संक्रमण UITransitionContextToViewControllerKey से दृश्य प्राप्त करके ठीक काम कर रहा है, लेकिन मेरा संक्रमण केवल संपूर्ण दृश्य में परिवर्तन लागू कर रहा है। मुझे यकीन नहीं है कि अगर manipulatingवीसी के विचारों के रूप में व्याख्या की जानी चाहिए या नहीं ...
मैथ्यू

1
वाह - यह पागल है। मैंने यह नहीं देखा कि यह अंतर है - शायद इसलिए कि यह केवल कुछ छोटी टिप्पणी है। वास्तव में निराशा होती है जब एप्पल इस तरह एक स्टंट खींचता है। उंगलियां आपके रडार से पार हो गईं।
ऐश फुरो

मैं viewForKeyजीएम में भी बग देख रहा हूं । क्या अन्य भी हैं? क्या आपको इसके लिए एक उचित समाधान मिला है?
rjkaplan

2
मैंने - viewForKey// viewForKey की टिप्पणी के अनुसार सोचा : शून्य वापस आ सकता है जो यह दर्शाता है कि एनिमेटर को संबंधित दृश्य नियंत्रक के दृश्य में हेरफेर नहीं करना चाहिए। लौटना nilबग नहीं है।
केन कुआन

4
@kenKuan आप सही हो सकते हैं। UIModalPresentationFullScreen का उपयोग करते समय, viewForKeyदृश्य और दृश्य से वापस करता है। तो शायद यह जानबूझकर है कि यह UIModalPresentationCustom के लिए शून्य देता है। मैं अपनी बग रिपोर्ट अपडेट कर रहा हूं और अगर मैं इसके बारे में Apple से वापस सुनता हूं तो यहां वापस पोस्ट करूंगा।
बेचेरी

24

modalPresentationStyleUIModalPresentationCustom के लिए सेट नहीं करना मेरे लिए समस्या तय की।

दूसरे शब्दों में, UIModalPresentationFullScreen को डिफ़ॉल्ट पर छोड़ने के बजाय UIModalPresentationCustom निर्दिष्ट करने के बजाय गायब दृश्य समस्या को ठीक किया। ध्यान दें कि UIViewControllerTransitioningDelegate प्रोटोकॉल अभी भी डिफ़ॉल्ट रूप से इसे छोड़ते समय अनुसरण किया जा रहा है। यदि मैं सही ढंग से याद करता हूं, तो एक बार UIModalPresentationCustom एक आवश्यकता थी।

अब तक काम करता है, केवल गैर-इंटरैक्टिव एनिमेशन के लिए यह कोशिश की है।


1
वाह। यह किया! मैंने iOS7 और 8 में modalPresentationStyle के बिना परीक्षण किया और यह दोनों में काम करता है। धन्यवाद!!
अह रयून मून

1
धन्यवाद! यह मेरे लिए सभी मुद्दों को हल viewForKey:करने के बजाय उपयोग करने के साथ संयुक्त है। .viewviewControllerForKey:
बचेरी

1
यह दृश्यदर्शी का उपयोग किए बिना मेरे लिए समस्या तय करता है, लेकिन मुझे लगता है कि इसका भी उपयोग किया जाना चाहिए।
केविन स्लिच

5
यद्यपि यह समस्या को ठीक करने के लिए लगता है, यह ध्यान रखना महत्वपूर्ण है कि आपके दृश्य नियंत्रक के पीछे की स्क्रीन प्रदर्शित होते ही काली हो जाएगी। यह महत्वपूर्ण है यदि आपका दृश्य नियंत्रक पूर्ण स्क्रीन नहीं है।
दोस्त 15

16

मुझे लेटरिस द्वारा संबंधित थ्रेड में यह अत्यंत उपयोगी उत्तर मिला है: https://stackoverflow.com/a/27165723/3704173

इसका सारांश प्रस्तुत करना:

  1. modalPresentationStyle को .Custom में सेट करें
  2. उपवर्ग UIPresentationController, ओवरराइड करना चाहिए
  3. अपनी ट्रांज़िशनडेलगेट श्रेणी में प्रस्तुति को रोकें

अपने कस्टम ट्रांज़िशन में +1, जब बर्खास्तगी एनीमेशन हो रहा हो, तो व्यू में न जोड़ें।

यहां प्रदर्शित:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 बिना किसी हैक के! यह जादू की तरह है! :)


1
यह वास्तविक सही उत्तर है। जादू की चाल के बिना स्वीकार किए जाते हैं। धन्यवाद, निशान!
आंद्रेई मैलेगिन

दुर्भाग्य से, यह iOS 12.4, Xcode 10.3 में काम नहीं करता है। स्क्रीन संक्रमण पूर्ण होने के बाद काला (सभी दृश्य पदानुक्रम से हटा दिया गया है बदल जाता है फिर भी, '.fullscreen' करता है काम चियर्स करने के लिए 'modalPresentationStyle' संपत्ति की
Womble

मैंने अपने प्रोजेक्ट में मार्क और gwinyai के स्विफ्ट कार्यान्वयन से ओबज-सी संस्करण की कोशिश की। दुर्भाग्य से उनमें से कोई भी उम्मीद के मुताबिक काम नहीं कर रहा है। मैं Xcode 11.1 का उपयोग कर रहा हूं और निर्माण लक्ष्य iOS 13.0 है, मैंने डिवाइस और सिम्युलेटर दोनों पर कोशिश की। मेरे मामले में, मेरा मूल सेट एक संग्रह दृश्य है और जब आप एक सेल को टैप करते हैं तो यह एनीमेशन के साथ एक विस्तृत दृश्य पर बहस करेगा। हालाँकि, यह पूरी तरह से ठीक काम करता है अगर मैं डिफ़ॉल्ट संक्रमण एनीमेशन का उपयोग कर रहा हूं। प्रस्‍तुत करने वाले वीसी तब नहीं जाएंगे जब मैं विवरणों को फिर से देखूंगा।
इन्फिनिटी_

8

IOS 8 में, आपको UIViewControllerTransitioningDelegate में एक UIPresentationController बनाने और नीचे दिए गए तरीके को लागू करने की आवश्यकता है।

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

जब एक दृश्य नियंत्रक पेश करते समय दृश्य पदानुक्रम के प्रबंधन के लिए उपयोग करने के लिए कस्टम प्रस्तुति नियंत्रक के लिए आपके प्रतिनिधि को पूछता है।

प्रतिलाभ की मात्रा:

मोडल प्रस्तुति के प्रबंधन के लिए कस्टम प्रस्तुति नियंत्रक।

चर्चा:

जब आप UIModalPresentationCustom प्रस्तुति शैली का उपयोग करके एक दृश्य नियंत्रक प्रस्तुत करते हैं, तो सिस्टम इस पद्धति को कॉल करता है और आपके कस्टम शैली का प्रबंधन करने वाले प्रस्तुति नियंत्रक के लिए पूछता है। यदि आप इस विधि को कार्यान्वित करते हैं, तो उस प्रस्तुति प्रस्तुति नियंत्रक ऑब्जेक्ट को बनाने और वापस करने के लिए इसका उपयोग करें जिसे आप प्रस्तुति प्रक्रिया का प्रबंधन करने के लिए उपयोग करना चाहते हैं।

यदि आप इस विधि को लागू नहीं करते हैं, या यदि आपका यह तरीका लागू नहीं होता है, तो सिस्टम डिफ़ॉल्ट प्रस्तुति नियंत्रक ऑब्जेक्ट का उपयोग करता है। डिफ़ॉल्ट प्रस्तुति नियंत्रक दृश्य पदानुक्रम में कोई दृश्य या सामग्री नहीं जोड़ता है।

उपलब्धता आईओएस 8.0 और बाद में उपलब्ध है।

अधिक जानकारी के लिए WWDC 2014 वीडियो देखें:

https://developer.apple.com/videos/wwdc/2014/?include=228

WWDC से एक नमूना कोड भी है जिसे "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects" कहा जाता है, जिसे आप WWDC 2014 के नमूना कोड पृष्ठ से डाउनलोड कर सकते हैं।

आपको नमूना कोड को थोड़ा बदलना होगा। UIPresentationController init विधि को निम्न में बदल दिया गया:

initWithPresentedViewController:presented presentingViewController:presenting

पहले उसे पेश किया गया और फिर प्रस्तुत किया गया। बस उन्हें स्वैप करें और यह काम करना चाहिए।


लिंक किए गए वीडियो को न देखने के लिए क्षमा करें, लेकिन मुझे नहीं लगता कि आपको कस्टम UIPresentationController की आवश्यकता है जब तक कि आप एनीमेशन के पूरा होने के बाद एक गैर-मानक प्रस्तुति नहीं चाहते, जैसे कि एक परिपत्र प्रस्तुत दृश्य। यदि आप सिर्फ एक अलग एनीमेशन चाहते हैं, तो UIViewControllerAnimatedTransitioning को लागू करना मेरे सीमित ज्ञान के आधार पर पर्याप्त होना चाहिए।
वदादी कार्तिक

7

इसके बजाय [इनवॉइस सम्मिलित करें: दृश्य: ऊपर का दृश्यप्रदर्शक.उपकरण से ऊपर का दृश्य: दृश्यदर्शी से। बस जोड़ें: [inView addSubview: toViewController.view];

if (self.presenting) {

    [transitionContext.containerView addSubview:toViewController.view];
    // your code

} else {
    // your code
}

आप यहां एक उदाहरण देख सकते हैं: लिंक और यह iOS 7 और iOS 8 पर काम करता है


यह UIModalPresentationStyleCustom प्रकार के एनीमेशन करने के लिए स्वीकृत उत्तर होना चाहिए क्योंकि कंटेनर व्यू में fromViewController को जोड़ने की कोई आवश्यकता नहीं है। आपको केवल वर्तमान एनीमेशन के दौरान toViewController को जोड़ने की आवश्यकता है।
स्कॉट कैसर

यह वास्तव में बहुत मददगार है
दिमित्री बोंडरेव

7

यहाँ ऐश के फिक्स का एक उद्देश्य सी संस्करण है।

// my attempt at obj-c version of Ash's fix
UIView *theToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
[[[UIApplication sharedApplication] keyWindow] addSubview:theToView];
[transitionContext completeTransition:YES]

मुझे ऑर्डर स्वैप करना पड़ा और [TransContext fullTransition:] विधि को कॉल करने के लिए वापस देखने के लिए एक नया व्यू कंट्रोलर प्रस्तुत करने के लिए एक अन्य व्यू कंट्रोलर की बर्खास्तगी पूर्ण ब्लॉक से सही काम करने के लिए।

मुझे नहीं पता कि यह इसे सभी के लिए ठीक कर देगा लेकिन यह मेरे ऐप में काम करता है। चीयर्स!


5

मैंने पाया कि यह ठीक काम के लिए Obj-C:

    [transitionContext completeTransition:YES];
    if(![[UIApplication sharedApplication].keyWindow.subviews containsObject:toViewController.view]) {
        [[UIApplication sharedApplication].keyWindow addSubview:toViewController.view];
    }

Ios7 और ios8 दोनों पर ठीक काम करने लगता है।


5

मैने पाया कि viewForKey:UITransitionContextToViewKey ios8 पर रिटर्न शून्य है। इसलिए यदि यह शून्य है, तो मैं व्यू को 'से' व्यू कंट्रोलर से पकड़ लेता हूं।

हालाँकि, यह 'से' देखने के परिणाम के लिए कंटेनर से खिड़की में नहीं ले जाया completeTransition:YESजाता है जब यह कहा जाता है। इसलिए अगर viewForKey:UITransitionContextToViewKeyवापसी होती है, तो मैं खत्म हो जाता हूंtoVC.view , और इस तथ्य का ध्यान रखता कि यह शून्य लौटा है, और पूरा होने के बाद मैं इसे कंटेनर के प्रारंभिक पर्यवेक्षक (जो खिड़की होता है) में ले जाता हूं।

तो यह कोड iOS7 के साथ-साथ iOS8 पर भी काम करता है , और iOS9 पर भी काम करना चाहिए , भले ही वे इसे ठीक करें या नहीं।

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    // Get the 'from' and 'to' views/controllers.
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    BOOL hasViewForKey = [transitionContext respondsToSelector:@selector(viewForKey:)]; // viewForKey is iOS8+.
    UIView *fromView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextFromViewKey] :
        fromVC.view;
    UIView *toView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextToViewKey] :
        toVC.view;

    // iOS8 has a bug where viewForKey:to is nil: http://stackoverflow.com/a/24589312/59198
    // The workaround is: A) get the 'toView' from 'toVC'; B) manually add the 'toView' to the container's
    // superview (eg the root window) after the completeTransition call.
    BOOL toViewNilBug = !toView;
    if (!toView) { // Workaround by getting it from the view.
        toView = toVC.view;
    }
    UIView *container = [transitionContext containerView];
    UIView *containerSuper = container.superview; // Used for the iOS8 bug workaround.

    // Perform the transition.
    toView.frame = container.bounds;
    [container insertSubview:toView belowSubview:fromView];
    [UIView animateWithDuration:kDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
        fromView.frame = CGRectOffset(container.bounds, 0, CGRectGetHeight(container.bounds));
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];

        if (toViewNilBug) {
            [containerSuper addSubview:toView];
        }
    }];
}

3

मैंने पाया कि यह बग (और भी कई!) सेट होने पर गायब हो जाता है modalPresentationStyle = UIModalPresentationFullScreen। आप निश्चित रूप से अभी भी अपने कस्टम संक्रमण एनीमेशन प्राप्त करते हैं।


2

मैं इस मुद्दे पर भी अटक गया। मैं एक अर्ध-पारदर्शी पृष्ठभूमि के साथ एक कस्टम संक्रमण बनाना चाह रहा था जहां मैं अभी भी देख सकता था कि मैं किस नियंत्रक को देख रहा था, लेकिन मुझे केवल एक काली पृष्ठभूमि मिली। मैंने पाया कि इस धागे में मार्क एरन के जवाब से मुझे मदद मिली लेकिन यह ऑब्जेक्टिव सी में लिखा गया है, इसलिए यहाँ उस उत्तर का एक स्विफ्ट 3 संस्करण है जिसे मैंने iOS 9 और iOS 10 के लिए परीक्षण किया है:

  1. UIPresentationController का एक उपवर्ग बनाएँ। इस प्रकार के रूप में गलत के लिए shouldRemovePresentersView ओवरराइड करें:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. जिस स्थान पर आप नए व्यू कंट्रोलर को इंस्टेंट कर रहे हैं और उसके ट्रांज़िशन प्रतिनिधि को सेट कर रहे हैं, संकेत मिलता है कि आप चाहते हैं कि यह एक कस्टम मोडल प्रस्तुति शैली निम्नानुसार हो:

    let newVC = mainStoryboard.instantiateViewController(withIdentifier: "newVC") as! NewViewController 
    
    newVC.transitioningDelegate = self
    
    newVC.modalPresentationStyle = UIModalPresentationStyle.custom
    
    newVC.modalPresentationCapturesStatusBarAppearance = true //optional
    
    present(newVC, animated: true, completion: nil)
  3. अब अपने UIViewControllerTransitioningDelegate की प्रस्तुति कंट्रोलर विधि को ओवरराइड करें और अपना कस्टम UIPresentationController वापस करें। मेरे पास मेरे वर्तमान वर्ग के विस्तार के रूप में मेरा था:

    extension CurrentViewController: UIViewControllerTransitioningDelegate {
    
    //this is where you implement animationController(forPresented) and animationController(forDismissed) methods
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    
    return ModalPresentationController(presentedViewController: presented, presenting: source)
    
    }
    }

ध्यान देने वाली एक और बात यह है कि आपको अपने प्रेजेंट एनीमेटर क्लास में अपने व्यूज को देखने की कोशिश नहीं करनी चाहिए। यह शून्य हो जाएगा और आपको रनटाइम में एक त्रुटि मिलेगी। इसके अलावा यदि आप चीजों को लागू करते हैं तो आप अपने एनीमेशन के साथ अपने कस्टम ट्रांज़िशन प्राप्त करेंगे और यदि आप एक बनाते हैं तो एक अर्ध-पारदर्शी पृष्ठभूमि।


यह iis स्विफ्ट 3 में एक कस्टम मोडल प्रस्तुति करने के लिए एक बेहतरीन उदाहरण है! धन्यवाद @gwinyai! मैं इस पर सुपर अटक गया जब तक कि मुझे एक उदाहरण नहीं मिला जिसने नई स्विफ्ट 3 एपीआई को दिखाया presentationController(forPresented presented UIViewController,... क्योंकि इसके लिए पिछले स्विफ्ट एपीआई ने कंप्लेंट को परेशान नहीं किया लेकिन बुलाया नहीं गया।
नतालिया

2

इस मुद्दे का सामना करने के बाद, मैं बहुत उलझन में था, क्योंकि मैंने लगभग बहुत समान नहीं बहुत पहले लिखा था जो ठीक काम करता है। यहाँ बहुत सुधार देखने के लिए जवाब खोजने के लिए आया था, और मूल कारण को समझने के लिए प्रतीत नहीं होता ... यह वास्तव में तय करने के लिए बहुत आसान है।

कुछ उत्तर बदलने modalPresentationStyleका उल्लेख करते हैं .overFullScreen। यह सही है, .overCurrentContextकाम भी करेगा। यह अपेक्षित है, और व्यवहार Apple दस्तावेज़। लेकिन यह सबके लिए काम क्यों नहीं कर रहा है? क्यों सभी hacky कोड, और इस के संयोजन के साथ कुछ और, और पागल सामान जो आपको नहीं करना चाहिए?

बाहर मुड़ता है, आपको प्रस्तुति शैली को देखने के पहले सेट करने की आवश्यकता है । बाद में नहीं। इसे init में करें, या पिछले कंट्रोलर से करें, या फिर जैसा चाहें तब करें - जब तक कि यह व्यू लोड से पहले है।


1
मैं .overCurrentContext दृश्य लोड ( initदृश्य नियंत्रक में) से पहले प्रस्तुति शैली सेट करता हूं और मुद्दा अभी भी होता है
रिकार्डोपेरेरा

1

नए UIModalPresentationOverCurrentContext का उपयोग करके इसे मेरे लिए निर्धारित किया गया है। IOS 7 पर मेरा मूल संक्रमण केवल मॉडल के नीचे के दृश्य की धुंधली पृष्ठभूमि होना था।


किसी कारण से, यह नीचे दिए गए दृश्य के साथ बातचीत की अनुमति नहीं देता है, जहां UIModalPresentationCurrentContext ने iOS 7 में किया था .. कोई विचार?
क्रिस्टोफर विर्ट

IOS 10 पर मेरे लिए Hmm। इस बग में .overContextxt परिणाम हैं लेकिन .fullscreen नहीं है। मैं यहाँ .overCurrentContext का उपयोग करने के लिए एक फिक्स के लिए उम्मीद कर रहा था, लेकिन अभी तक ऐसा कुछ भी नहीं लगता है कि यह iOS 10 में काम करेगा सिवाय शायद UIPresentationController को छोड़कर ...
नतालिया

0

ठीक है, दोस्तों, मुझे लगता है कि मैं एक मामले को हल करता हूं कि जब आप iOS 13 और इसके बाद के संस्करण में ऐप बनाते हैं तो 'एक काम करने वाला एनिमेटर' ठीक से काम करना बंद कर देता है।

env Xcode 11.1, iOS 13.1

संकट

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

मैंने अपने संग्रह VC से विस्तार VC तक ड्रैग-एंड-ड्रॉप द्वारा IB में segue की स्थापना की। Segue की शैली 'Present modally' है और प्रस्तुति 'Full Screen' पर सेट है।

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

1. निम्नलिखित पंक्ति के बाद फ़ंक्शन 'चेतनट्रेनशन ()' से कॉल किया जाता है, संग्रह दृश्य फिर से शुरू होता है और दिखाता है

transitionContext.completeTransition(true)

2. जब तक डिटेल व्यू पूरी तरह से कलेक्शन व्यू को कवर नहीं कर देता, तब तक डिटेल व्यू से वापस आने पर कलेक्शन व्यू गायब नहीं होगा

उपाय

ईमानदार होने के लिए, मुझे थोड़ा पता है कि एनिमेटेड संक्रमण कैसे काम करता है। इसलिए मैं केवल इस पोस्ट और दूसरे का अनुसरण कर सकता हूं , प्रत्येक उत्तर का प्रयास कर सकता हूं । दुर्भाग्य से, उनमें से कोई भी मेरे लिए काम नहीं करता है। अंत में, मैं एक बिंदु पर आया, जहां केवल एक चीज जो मैं ट्विस्ट कर सकता हूं, वह आईबी में सेग की प्रस्तुति शैली है (जो मुझे बहुत शुरुआत में करनी चाहिए थी)। जब मैंने प्रस्तुति को Full ओवर फुल स्क्रीन ’पर सेट किया, तो चमत्कार होता है और मेरी समस्या हल हो जाती है। विस्तार दृश्य एनीमेशन के साथ पूर्ण स्क्रीन में दिखा सकता है और जब इसे खारिज कर दिया जाता है, तो मैं दोनों संग्रह दृश्य को पृष्ठभूमि और एनिमेटेड विस्तार दृश्य के रूप में देख सकता हूं।

फिर सड़क के किनारे एक और खोज

3. निम्नलिखित तरीकों से काम करने के लिए 'toView' और 'fromView' का संदर्भ लें

अप्रत्यक्ष तरीके से:

transitionContext.viewController(forKey: .to)?.view
transitionContext.viewController(forKey: .from)?.view

सीधा रास्ता:

transitionContext.view(forKey: .to)
transitionContext.view(forKey: .from)

लेकिन जब मैंने सेग स्टाइल को 'ओवर फुल स्क्रीन' में बदल दिया, तो सीधे 'एनडब्ल्यूई' और 'व्यू व्यू' दोनों के लिए 'नील' लौटाया और केवल अप्रत्यक्ष तरीके से काम किया, इस समस्या का उल्लेख किसी अन्य पोस्ट में भी किया गया है , इसलिए मुझे लगता है कि यह इसके लायक है मेरी छोटी सी खोज यहाँ पोस्ट करने के लिए।

आशा है कि यह भविष्य में किसी के लिए उपयोगी होगा।


0

कंटेंट व्यू कंट्रोलर को खारिज करते समय मुझे भी यही समस्या थी।

मेरे ऐप में यह पेरेंट व्यू कंट्रोलर है जो कि चाइल्ड व्यू कंट्रोलर (प्रेजेंटिंग वीसी) को मामूली रूप से दिखाता है। फिर जब चाइल्डवीसी में एक सबव्यू टैप किया जाता है, तो यह एक और vc दिखाता है (जिसे मैं कंटेंट व्यू कंट्रोलर (प्रेजेंट सीसी) कह रहा हूं)

मेरी समस्या यह है कि जब कंटेंटवीसी (अब प्रेजेंटिंग वीसी) को खारिज कर दिया जाए, तो उसे चाइल्ड वीसी (अब प्रेजेंट वीसी) के पास जाना चाहिए, लेकिन जैसे ही मेरा कस्टम ट्रांजिशन खत्म होता है, पैरेंट वीसी को दिखाते हुए चाइल्डवैक अचानक गायब हो जाता है।

मैंने इस मुद्दे को हल करने के लिए जो किया वह है

  1. बदल .modalPresentationStylechildVC के डिफ़ॉल्ट से parentVC द्वारा प्रस्तुत .automaticकरने के लिए .fullscreen
  2. फिर .modalPresentationStyleकंटेंटवीसी को भी बदल दिया .fullscreen

यह समस्या को हल करता है। लेकिन यह आपके बच्चे के वीसी को माता-पिता के शीर्ष पर कार्ड-स्टाइल शीट के रूप में नहीं दिखाएगा (जब उपयोग .overCurrentContextया स्वचालित) जो कि iOS 13 में नया है।

यह जानना पसंद करेंगे कि क्या कोई समाधान है जो माता-पिता द्वारा प्रस्तुत किए जाने पर चाइल्डवीसी के लिए कार्ड-स्टाइल शीट को बरकरार रखेगा।


-3

एक अन्य दृश्य नियंत्रक के एक बच्चे के रूप में एक दृश्य नियंत्रक जोड़ता है।

[self addChildViewController:childViewController];                 

जाँच करें और मुझे बताएं।


मुझे नहीं मिल रहा है, क्या आप इसे कोडिंग का उपयोग करके वर्णन कर सकते हैं?
नीरवपल्ले

इस ऐप्पल डॉक्यूमेंटेशन डेवलपर की
रुषभ

यह किसी भी तरह से सवाल का जवाब नहीं देता है। चाइल्डव्यूकंट्रोलर कस्टम बदलाव के किसी भी हिस्से में शामिल नहीं हैं, वे एक पूरी तरह से अलग विषय हैं।
एम।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.