在容器视图中交换子视图 [英] Swapping child views in a container view
问题描述
让 ContainerView
成为具有两个子内容视图的父容器视图:NavigationView
和 ContentView
.
Let ContainerView
be the parent container view with two child content views: NavigationView
and ContentView
.
我希望能够用另一个视图替换 ContentView
的控制器.例如,用新闻页面控制器交换主页控制器.目前,我能想到的唯一方法是使用委托来告诉 ContainerView
我想切换视图.这似乎是一种草率的方法,因为 ContainerViewController
最终会为所有子视图提供一堆特殊的委托.
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.
这还需要与 NavigationView
通信,后者具有关于当前在 ContentView
中的视图的信息.例如:如果用户在新闻页面,导航视图中的导航栏会显示当前选择了新闻按钮.
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.
问题 A:有没有办法在 ContentView
中交换控制器而无需调用 ContainerView
本身的委托方法?我想以编程方式执行此操作(无故事板).
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).
问题 B:如何在没有委托调用的情况下从 NavigationView
交换 ContentView
中的控制器?我想以编程方式执行此操作(无故事板).
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];
}];
当你这样做时,内容视图的控制器不需要任何委托协议接口(除了 iOS 已经提供的 在自定义容器中管理子视图控制器方法).
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:
为此定义一个协议:
Define a protocol for this:
@protocol ContainerParent <NSObject>
- (void)changeContentTo:(UIViewController *)controller;
@end
定义父控制器以符合此协议,例如:
Define the parent controller to conform to this protocol, e.g.:
#import <UIKit/UIKit.h>
#import "ContainerParent.h"
@interface ViewController : UIViewController <ContainerParent>
@end
在父控制器中实现 changeContentTo
方法(很像上面概述的):
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];
}];
}
并且子控制器现在可以参考 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];
}
这篇关于在容器视图中交换子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!