2013-11-21 10 views
13

तो मेरे पास एक नियंत्रक ए के साथ रूट नियंत्रक के रूप में एक UINavigationController है।आईओएस 7 कस्टम इंटरैक्टिव संक्रमण का उपयोग केवल कुछ समय

जब मैं शीर्ष पर नियंत्रक बी को धक्का देना चाहता हूं, तो मैं एक कस्टम एनिमेटेड संक्रमण और कस्टम इंटरैक्टिव संक्रमण का उपयोग करना चाहता हूं। यह ठीक काम करता है।

जब मैं शीर्ष पर नियंत्रक सी पुश करने के लिए चाहते हैं, तो मैं डिफ़ॉल्ट धक्का/पॉप संक्रमण कि UINavigationController के साथ आता है में वापस आने का चाहते हैं। बनाने के लिए यह मैं

navigationController:animationControllerForOperation:fromViewController:toViewController: 

तथापि के लिए वापस नहीं के बराबर है, तो आप नहीं के बराबर वापसी हो, तो

navigationController:interactionControllerForAnimationController: 

कभी नहीं बुलाया जाएगा और डिफ़ॉल्ट "बाएं किनारे से पैन" पॉप इंटरैक्टिव संक्रमण काम नहीं करता।

क्या डिफ़ॉल्ट पुश/पॉप एनीमेशन नियंत्रक और इंटरैक्शन नियंत्रक को वापस करने का कोई तरीका है? (क्या id<UIViewControllerAnimatedTransitioning> और id<UIViewControllerInteractiveTransitioning> के ठोस कार्यान्वयन हैं?)

या कोई अन्य तरीका?

उत्तर

18

आप स्वयं को navigationController के interactivePopGestureRecognizer प्रतिनिधि सेट और फिर -gestureRecognizerShouldBegin में अपने व्यवहार को संभाल चाहिए:

है यही कारण है, आप चाहते हैं जब में निर्मित पॉप इशारा आग, आप इस विधि से हाँ लौट जाना चाहिए। आपके कस्टम इशारे के लिए भी यही है - आपको यह पता लगाना होगा कि आप किस पहचानकर्ता से निपट रहे हैं।

- (void)setup 
{ 
    self.interactiveGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTransitionGesture:)]; 
    self.interactiveGestureRecognizer.delegate = self; 
    [self.navigationController.view addGestureRecognizer:self.interactiveGestureRecognizer]; 

    self.navigationController.interactivePopGestureRecognizer.delegate = self; 
} 

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
{ 
    // Don't handle gestures if navigation controller is still animating a transition 
    if ([self.navigationController.transitionCoordinator isAnimated]) 
     return NO; 

    if (self.navigationController.viewControllers.count < 2) 
     return NO; 

    UIViewController *fromVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-1]; 
    UIViewController *toVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-2]; 

    if ([fromVC isKindOfClass:[ViewControllerB class]] && [toVC isKindOfClass:[ViewControllerA class]]) 
    { 
     if (gestureRecognizer == self.interactiveGestureRecognizer) 
      return YES; 
    } 
    else if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) 
    { 
     return YES; 
    } 

    return NO; 
} 

आप अपने परिदृश्य के लिए sample project देख सकते हैं। दृश्य नियंत्रकों ए और बी के बीच संक्रमण कस्टम एनिमेटेड हैं, कस्टम बी-> एक पॉप इशारा के साथ। अंतर्निहित नेविगेशन नियंत्रक के पॉप इशारे के साथ व्यू कंट्रोलर बी और सी के बीच संक्रमण डिफ़ॉल्ट हैं।

आशा है कि इससे मदद मिलती है!

+0

एप्पल पर डीटीएस लोगों के अनुसार, निजी interactivePopGestureRecognizer कि UINavigationController के साथ जहाजों अपने प्रतिनिधि में चेक, जिनमें से कुछ निजी एपीआई में फोन के एक नंबर है। अपने स्वयं के प्रतिनिधि को लागू करने के लिए सभी मामलों में से 100% को कवर करने की गारंटी नहीं है। – Ziconic

+0

@ ज़िकोनिक उदाहरण केस? – Andy

0

अपना कस्टम संक्रमण करने के बाद (self.)navigationController.delegatenil (या इसे पिछले मान पर वापस लौटें) को सेट करने का प्रयास करें।

10

आपको प्रस्तुत करने से पहले हर बार प्रतिनिधि को सेट करने की आवश्यकता होगी - तैयार में फोर्ससेक: उदाहरण के लिए। यदि आप कस्टम संक्रमण चाहते हैं, तो इसे स्वयं पर सेट करें। यदि आप डिफ़ॉल्ट संक्रमण (डिफ़ॉल्ट पॉप संक्रमण की तरह) चाहते हैं तो इसे शून्य पर सेट करें।

+1

अफसोस की बात यह है कि यह वास्तव में सही उत्तर है और ऐप्पल डीटीएस लोगों की सिफारिश है कि यह एक विशेष रूप से सुरुचिपूर्ण नहीं है। असल में आपको 2 UINavigationControllerDelegate ऑब्जेक्ट्स की आवश्यकता होती है, जो संक्रमण कॉलबैक लागू करता है और वह जो (या शून्य नहीं है)। डिफ़ॉल्ट पॉप संक्रमण प्राप्त करने के लिए, कॉलबैक के बिना प्रतिनिधि का उपयोग करें (या प्रतिनिधि को शून्य पर सेट करें)। कस्टम संक्रमण प्राप्त करने के लिए, कॉलबैक वाले प्रतिनिधि के लिए प्रतिनिधि को स्वैप करें (और संक्रमण पूर्ण होने के बाद मूल प्रतिनिधि को पुनर्स्थापित करें)। – Ziconic

+0

क्या यह अभी भी अनुशंसित दृष्टिकोण है? – ken

+0

@ken यह आईओएस 7 और 8 में काम करता है इसलिए मैं हाँ कहूंगा। – Jesse

0

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

मेरे पास working example on github है।

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController 
{ 
    // Unset the delegate so that all other types of transitions (back, normal animated push not initiated by a gesture) get the default behavior. 
    self.navigationController.delegate = nil; 

    if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan) { 
    self.percentDrivenInteractiveTransition = [UIPercentDrivenInteractiveTransition new]; 
    } else { 
    self.percentDrivenInteractiveTransition = nil; 
    } 

    return self.percentDrivenInteractiveTransition; 
} 
1

से पहले प्रतिनिधि स्थापना/के रूप में Ziconic ने सुझाव दिया या के साथ खेलने के बाद एक संक्रमण एक मान्य समाधान नहीं है, लेकिन यदि आप अन्य UINavigationControllerDelegate के तरीकों को लागू करने और आप उन्हें रखने की जरूरत है, आप या तो 2 प्रतिनिधि वस्तुओं हो सकता है एनएसओब्जेक्ट का respondsToSelector:।अपने नेविगेशन प्रतिनिधि में आप को लागू कर सकते हैं:

- (BOOL)respondsToSelector:(SEL)aSelector 
{ 
    if (aSelector == @selector(navigationController:animationControllerForOperation:fromViewController:toViewController:) || 
     aSelector == @selector(navigationController:interactionControllerForAnimationController:)) { 

     return self.interactivePushTransitionEnabled; 
    } 

    return [super respondsToSelector:aSelector]; 
} 

फिर आप को अपडेट करना सुनिश्चित interactivePushTransitionEnabled रूप में की जरूरत बनाना चाहिए। आपके उदाहरण में, आपको केवल YES पर प्रॉपर्टी सेट करनी चाहिए जब नियंत्रक ए प्रदर्शित किया जा रहा हो।

ऐसा करने के लिए केवल एक और चीज है: अपने प्रतिनिधि द्वारा लागू विधियों का पुनर्मूल्यांकन करने के लिए UINavigationController को मजबूर करें। यह आसानी से कुछ इस तरह कर रही द्वारा किया जा सकता:

navigationController.delegate = nil; 
navigationController.delegate = self; // or whatever object you use as the delegate 
संबंधित मुद्दे