在容器视图中交换子视图 [英] Swapping child views in a container view

查看:105
本文介绍了在容器视图中交换子视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ContainerView成为具有两个子内容视图的父容器视图:NavigationViewContentView.

我希望能够用另一个视图换出ContentView的控制器.例如,将主页控制器与新闻页面控制器交换.目前,我唯一想到的方法是使用委托告诉ContainerView我要切换视图.这似乎是一种草率的方法,因为ContainerViewController最终将为所有子视图提供一堆特殊的委托.

这还需要与NavigationView进行通信,后者具有有关ContentView中当前哪个视图的信息.例如:如果用户在新闻页面上,则导航视图中的导航栏将显示当前已选择新闻按钮.

问题A: 有没有一种方法可以在ContentView中交换控制器而无需调用ContainerView本身的委托方法?我想以编程方式执行此操作(没有情节提要).

问题B: 如何在没有委托调用的情况下从NavigationView交换ContentView中的控制器?我想以编程方式执行此操作(没有情节提要).

解决方案

当子视图具有自己的视图控制器时,应遵循自定义容器控制器模式.请参阅创建自定义容器视图控制器以获取更多信息.

假设您遵循了自定义容器模式,那么当您想更改内容视图"的子视图控制器(及其关联的视图)时,可以通过类似以下操作的方式进行操作:

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

以这种方式进行操作时,不需要与内容视图的控制器建立任何委托协议接口(iOS已通过

  • 在父控制器中实现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];
                                }];
    }
    

  • 并且子控制器现在可以参考iOS为您提供的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];
    }
    

  • Let ContainerView be the parent container view with two child content views: NavigationView and ContentView.

    I would like to be able to swap out the controller of ContentView with another view. For example, swapping a home page controller with a news page controller. Currently, the only way I can think to do this is by using a delegate to tell the ContainerView that I want to switch views. This seems like a sloppy way to do this because the ContainerViewController would end up having a bunch of special delegates for all of the subviews.

    This also needs to communicate with the NavigationView which has information about which view is currently in the ContentView. For example: if the user is on the news page, the navigation bar within the navigation view will show that the news button is currently selected.

    Question A: Is there a way to swap the controller in ContentView without a delegate method calling the ContainerView itself? I would like to do this programmatically (no storyboard).

    Question B: How can I swap controllers in ContentView from the NavigationView without a delegate call? I would like to do this programmatically (no storyboard).

    解决方案

    When you have child views that have their own view controllers, you should be following the custom container controller pattern. See Creating Custom Container View Controllers for more information.

    Assuming you've followed the custom container pattern, when you want to change the child view controller (and its associated view) for the "content view", you would do that programmatically with something like:

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

    When you do it this way, there's no need for any delegate-protocol interface with the content view's controller (other than what iOS already provides with the Managing Child View Controllers in a Custom Container methods).


    By the way, this assumes that the initial child controller associated with that content view was added like so:

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


    If you want a child controller to tell the parent to change the controller associated with the content view, you would:

    1. Define a protocol for this:

      @protocol ContainerParent <NSObject>
      
      - (void)changeContentTo:(UIViewController *)controller;
      
      @end
      

    2. Define the parent controller to conform to this protocol, e.g.:

      #import <UIKit/UIKit.h>
      #import "ContainerParent.h"
      
      @interface ViewController : UIViewController <ContainerParent>
      
      @end
      

    3. Implement the changeContentTo method in the parent controller (much as outlined above):

      - (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. And the child controllers can now use this protocol in reference to the self.parentViewController property that iOS provides for you:

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

    这篇关于在容器视图中交换子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆