[英]Swapping child views in a container view
让ContainerView
成为具有两个子内容视图的父容器视图: NavigationView
和ContentView
。
我希望能够将ContentView
的控制器换成另一个视图。 例如,使用新闻页面控制器交换主页控制器。 目前,我能想到的唯一方法是使用委托来告诉ContainerView
我想要切换视图。 这似乎是一种草率的方式,因为ContainerViewController
最终会为所有子视图提供一堆特殊的委托。
这还需要与NavigationView
进行通信, 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已经在自定义容器方法中管理子视图控制器提供的接口)。
顺便说一下,这假设与该内容视图关联的初始子控制器是这样添加的:
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];
如果您希望子控制器告诉父级更改与内容视图关联的控制器,您将:
为此定义协议:
@protocol ContainerParent <NSObject> - (void)changeContentTo:(UIViewController *)controller; @end
定义父控制器以符合此协议,例如:
#import <UIKit/UIKit.h> #import "ContainerParent.h" @interface ViewController : UIViewController <ContainerParent> @end
在父控制器中实现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]; }
对于这种过渡,您还可以使用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
,过渡等。
你好像很困惑。 contentView(假设UIView
)不包含您要换出的控制器。 UIViewController
处理它的UIView。 在我看来,您需要父子视图控制器设置。
单个父视图控制器,它将处理子视图控制器,然后您可以在屏幕上显示每个视图控制器时处理每个控制器,并相应地调整您的UIViews和内容。 请参阅下面的Apple文档。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.