2013-10-03 7 views
22

ContainerView दो बच्चे सामग्री दृश्यों के साथ मूल कंटेनर दृश्य बनें: NavigationView और ContentViewएक कंटेनर व्यू में बच्चे के दृश्यों को स्वैप करना

Example of View Layout

मैं एक दृश्य के साथ ContentView के नियंत्रक बाहर स्वैप करने में सक्षम होना चाहते हैं। उदाहरण के लिए, एक समाचार पृष्ठ नियंत्रक के साथ एक होम पेज नियंत्रक स्वैपिंग। वर्तमान में, ऐसा करने का एकमात्र तरीका यह है कि ContainerView को बताने के लिए एक प्रतिनिधि का उपयोग करके मैं विचारों को स्विच करना चाहता हूं। ऐसा करने के लिए यह एक बेवकूफ तरीका लगता है क्योंकि ContainerViewController सभी सबव्यू के लिए विशेष प्रतिनिधियों का समूह बन जाएगा।

इसे NavigationView के साथ संवाद करने की भी आवश्यकता है जिसमें इस बारे में जानकारी है कि वर्तमान में ContentView में कौन सा दृश्य है। उदाहरण के लिए: यदि उपयोगकर्ता समाचार पृष्ठ पर है, तो नेविगेशन व्यू के भीतर नेविगेशन बार दिखाएगा कि समाचार बटन वर्तमान में चुना गया है।

प्रश्न एक: वहाँ एक प्रतिनिधि विधि ContainerView ही बुला बिना ContentView में नियंत्रक स्वैप करने के लिए कोई तरीका है? मैं इसे प्रोग्रामेटिक रूप से करना चाहता हूं (कोई स्टोरीबोर्ड नहीं)।

प्रश्न बी: ​​ मैं कैसे एक प्रतिनिधि कॉल बिना NavigationView से ContentView में नियंत्रकों स्वैप कर सकते हैं? मैं इसे प्रोग्रामेटिक रूप से करना चाहता हूं (कोई स्टोरीबोर्ड नहीं)।

+2

क्या आपने UIPageViewController पर एक नज़र डाली? "एक पृष्ठ दृश्य नियंत्रक उपयोगकर्ता को सामग्री के पृष्ठों के बीच नेविगेट करने देता है, जहां प्रत्येक पृष्ठ को अपने स्वयं के व्यू कंट्रोलर ऑब्जेक्ट द्वारा प्रबंधित किया जाता है" – shadowhorst

उत्तर

37

जब आप बच्चे को अपने स्वयं के विचारों दृश्य नियंत्रक है कि है, तो आप कस्टम कंटेनर नियंत्रक पैटर्न निम्नलिखित होना चाहिए। अधिक जानकारी के लिए Creating Custom Container View Controllers देखें।

मान लिया जाये कि आप कस्टम कंटेनर पैटर्न का पालन किया है, जब आप (और इससे संबंधित दृश्य) "सामग्री को देखने के लिए" बच्चे दृश्य नियंत्रक को बदलना चाहते हैं, तो आप उस प्रोग्राम के रूप में करना होगा की तरह कुछ के साथ:

UIViewController *newController = ... // instantiate new controller however you want 
UIViewController *oldController = ... // grab the existing controller for the current "content view"; perhaps you maintain this in your own ivar; perhaps you just look this up in self.childViewControllers 

newController.view.frame = oldController.view.frame; 

[oldController willMoveToParentViewController:nil]; 
[self addChildViewController:newController];   // incidentally, this does the `willMoveToParentViewController` for the new controller for you 

[self transitionFromViewController:oldController 
        toViewController:newController 
          duration:0.5 
          options:UIViewAnimationOptionTransitionCrossDissolve 
         animations:^{ 
          // no further animations required 
         } 
         completion:^(BOOL finished) { 
          [oldController removeFromParentViewController]; // incidentally, this does the `didMoveToParentViewController` for the old controller for you 
          [newController didMoveToParentViewController:self]; 
         }]; 

जब आप इसे इस तरह करते हैं, तो सामग्री दृश्य नियंत्रक के साथ किसी भी प्रतिनिधि-प्रोटोकॉल इंटरफ़ेस की आवश्यकता नहीं होती है (आईओएस पहले से ही Managing Child View Controllers in a Custom Container विधियों के साथ प्रदान करता है) के अलावा।


वैसे, इस मानता है कि प्रारंभिक बच्चे उस सामग्री को देखने के साथ जुड़े नियंत्रक तो जैसे जोड़ा गया है:

UIViewController *childController = ... // instantiate the content view's controller any way you want 
[self addChildViewController:childController]; 
childController.view.frame = ... // set the frame any way you want 
[self.view addSubview:childController.view]; 
[childController didMoveToParentViewController:self]; 

आप एक बच्चे नियंत्रक माता पिता को बताने के लिए बदलना चाहते हैं सामग्री दृश्य से जुड़े नियंत्रक, आप:

  1. इसके लिए प्रोटोकॉल परिभाषित करें:

    @protocol ContainerParent <NSObject> 
    
    - (void)changeContentTo:(UIViewController *)controller; 
    
    @end 
    
  2. इस प्रोटोकॉल के अनुरूप माता-पिता नियंत्रक को परिभाषित करें जैसे,: (ज्यादा जैसा कि ऊपर उल्लिखित)

    #import <UIKit/UIKit.h> 
    #import "ContainerParent.h" 
    
    @interface ViewController : UIViewController <ContainerParent> 
    
    @end 
    
  3. लागू माता पिता नियंत्रक में changeContentTo विधि:

    - (void)changeContentTo:(UIViewController *)controller 
    { 
        UIViewController *newController = controller; 
        UIViewController *oldController = ... // grab reference of current child from `self.childViewControllers or from some property where you stored it 
    
        newController.view.frame = oldController.view.frame; 
    
        [oldController willMoveToParentViewController:nil]; 
        [self addChildViewController:newController]; 
    
        [self transitionFromViewController:oldController 
             toViewController:newController 
               duration:1.0 
               options:UIViewAnimationOptionTransitionCrossDissolve 
              animations:^{ 
               // no further animations required 
              } 
              completion:^(BOOL finished) { 
               [oldController removeFromParentViewController]; 
               [newController didMoveToParentViewController:self]; 
              }]; 
    } 
    
  4. और बच्चे नियंत्रक अब इस प्रोटोकॉल का उपयोग self.parentViewController संपत्ति के संदर्भ में कर सकते हैं जो आईओएस आपके लिए प्रदान करता है:

    - (IBAction)didTouchUpInsideButton:(id)sender 
    { 
        id <ContainerParent> parentViewController = (id)self.parentViewController; 
        NSAssert([parentViewController respondsToSelector:@selector(changeContentTo:)], @"Parent must conform to ContainerParent protocol"); 
    
        UIViewController *newChild = ... // instantiate the new child controller any way you want 
        [parentViewController changeContentTo:newChild]; 
    } 
    
+0

यह मैंने गिटहब पर अधिकांश कंटेनर व्यू कार्यान्वयन में देखा है और इसे दस्तावेज़ीकरण से अनुमानित किया है। क्या इस कोड को प्रत्येक नियंत्रक में डुप्लिकेट किए बिना ऐसा करने का कोई तरीका है? – Alex

+1

@orbv यह कोड केवल मूल नियंत्रक में है, इसलिए इसमें कोई डुप्लिकेशन शामिल नहीं है। शायद मैं आपके प्रश्न को समझ नहीं रहा हूं। – Rob

+1

एक्सकोड 5 एक कंटेनर व्यू जोड़ते समय आपको एक एम्बेड सीगू का उपयोग करने देता है। यदि ऑटो-लेआउट का उपयोग किया जा रहा है तो मैं फ्रेम को सीधे सेट करने से भी बचूंगा। – Abizern

-2

आपको उलझन में लग रहा है। एक सामग्री दृश्य (UIView मानते हुए) में एक नियंत्रक 'शामिल' नहीं होता है जिसे आप स्वैप कर देंगे। एक UIViewController अपने UIView को संभालता है। ऐसा लगता है कि आपको माता-पिता-बच्चे दृश्य नियंत्रक सेटअप की आवश्यकता है।

एक एकल अभिभावक दृश्य नियंत्रक, जो बाल दृश्य नियंत्रकों को संभालेगा, जिनमें से प्रत्येक स्क्रीन पर दिखाए जाने पर आपके द्वारा नियंत्रित किए जाने पर प्रत्येक यूआईवी व्यू और सामग्री को समायोजित कर सकता है। कृपया नीचे एप्पल दस्तावेज देखें।

Container Programming - Apple Documentation

2

संक्रमण इस तरह आप भी UIView.animateWith... एनिमेशन का उपयोग कर सकते हैं।

उदाहरण के लिए, मान लेते हैं कि rootContainerView कंटेनर और कंटेनर में contentViewController वर्तमान में सक्रिय नियंत्रक, तो

func setContentViewController(contentViewController:UIViewController, animated:Bool = true) { 
    if animated == true { 
     addChildViewController(contentViewController) 
     contentViewController.view.alpha = 0 
     contentViewController.view.frame = rootContainerView.bounds 
     rootContainerView.addSubview(contentViewController.view) 
     self.contentViewController?.willMoveToParentViewController(nil) 

     UIView.animateWithDuration(0.3, animations: { 
      contentViewController.view.alpha = 1 
      }, completion: { (_) in 
       contentViewController.didMoveToParentViewController(self) 

       self.contentViewController?.view.removeFromSuperview() 
       self.contentViewController?.didMoveToParentViewController(nil) 
       self.contentViewController?.removeFromParentViewController() 
       self.contentViewController = contentViewController 
     }) 
    } else { 
     cleanUpChildControllerIfPossible() 

     contentViewController.view.frame = rootContainerView.bounds 
     addChildViewController(contentViewController) 
     rootContainerView.addSubview(contentViewController.view) 
     contentViewController.didMoveToParentViewController(self) 
     self.contentViewController = contentViewController 
    } 
} 

// MARK: - Private 

private func cleanUpChildControllerIfPossible() { 
    if let childController = contentViewController { 
     childController.willMoveToParentViewController(nil) 
     childController.view.removeFromSuperview() 
     childController.removeFromParentViewController() 
    } 
} 

इस यू सरल फीका एनिमेशन प्रदान करती है, यू भी किसी भी UIViewAnimationOptions कोशिश कर सकते हैं कर सकते हैं, संक्रमण आदि

संबंधित मुद्दे