在iOS 5之前苹果是不允许出现自定义的Container的 ,也就是说你创建的一个View Controller的view不能包含另一个View Controller的view,这对于逻辑复杂的界面来说,不易于功能拆分。也许曾经你为了某个公用的显示逻辑,直接将某个View Controller的view添加到另一个View Controller的view上,然后发现可以正常显示和使用,但实际上这种行为是非常危险的。
iOS 5.0 开始支持Custom Container View Controller,开放了用于构建自定义Container的接口。如果你想创建一个自己的Container,那么有一些概念还得弄清楚。Container的主要职责就是管理一个或多个Child View Controller的展示的生命周期,需要传递显示以及旋转相关的回调。
其实显示或者旋转的回调的触发的源头来自于window,一个app首先有一个主window,初始化的时候需要给这个主window指定一个rootViewController,window会将显示相关的回调(viewWillAppear:, viewWillDisappear:, viewDidAppear:, or viewDidDisappear: )以及旋转相关的回调(willRotateToInterfaceOrientation:duration: ,willAnimateRotationToInterfaceOrientation:duration:, didRotateFromInterfaceOrientation:)传递给rootViewController。rootViewController需要再将这些callbacks的调用传递给它的Child View Controllers。
一. 父子关系范式
实现一个Custom Container View Controller并不是一个简单的事情,主要分为两个阶段:父子关系的建立以及父子关系的解除。如果pVC将cVC的view添加为自己的subview,那么cVC必须为pVC的Child View Controller,而反过来则不一定成立,比如UINavigationController,一个View Controller被push进来后便和navigationController建立父子关系了,但是只有最上面的View Controller 是显示着的,底下的View Controller的view则被移出了容器的view的显示层级,当一个View Controller被pop之后,便和navigationController解除了父子关系了。
展示一个名为content的child view controller:
- [self addChildViewController:content]; //1
- content.view.frame = [self frameForContentController];
- [self.view addSubview:self.currentClientView]; //2
- [content didMoveToParentViewController:self]; //3
1.将content添加为child view controller,addChildViewController:接口建立了逻辑上的父子关系,子可以通过parentViewController,访问其父VC,addChildViewController:接口的逻辑中会自动调用 [content willMoveToParentViewController:self];
2.建立父子关系后,便是将content的view加入到父VC的view hierarchy上,同时要决定的是 content的view显示的区域范围。
3.调用child的 didMoveToParentViewController: ,以通知child,完成了父子关系的建立
移除一个child view controller:
- [content willMoveToParentViewController:nil]; //1
- [content.view removeFromSuperview]; //2
- [content removeFromParentViewController]; //3
1.通知child,即将解除父子关系,从语义上也可以看出 child的parent即将为nil
2.将child的view从父VC的view的hierarchy中移除
3.通过removeFromParentViewController的调用真正的解除关系,removeFromParentViewController会自动调用 [content didMoveToParentViewController:nil]
代码实现部分,封装的一个简单视图控制类管理切换视图功能
@interface ContaintControllerHealp ()<TopSortChooseDelegate>
@property (nonatomic, strong)UIViewController *currentVC;//保存当前选择的VC
@property (nonatomic, strong)NSArray *controllers;
@property (nonatomic, strong)UIViewController *fatherVC;
@end
@implementation ContaintControllerHealp
-(instancetype)initByCeateContainWithControllers:(NSArray *)controllers titles:(NSArray *)titles fatherController:(UIViewController *) fahterVC{
self = [super init];
if (self) {
fahterVC.automaticallyAdjustsScrollViewInsets = NO;
self.fatherVC = fahterVC;
self.controllers = controllers;
[self creatTopSegmentWithTitles:titles fatherC:fahterVC];
[self createControllerResolutionWith:controllers fatherVC:fahterVC];
}
return self;
}
//
-(void)creatTopSegmentWithTitles:(NSArray *)titles fatherC:(UIViewController *)fahterVC{
CunstomTopScrollView *customScro = [[CunstomTopScrollView alloc] initWithFrame:CGRectMake(0, 64, fahterVC.view.frame.size.width, 40) titileArr:titles];
customScro.delegate = self;
[fahterVC.view addSubview:customScro];
}
-(void)createControllerResolutionWith:(NSArray *)controllers fatherVC:(UIViewController *)fatherVC{
//拿第一个VC而已。。写麻烦了
[controllers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIViewController *VC = obj;
if (idx == 0) {//默认第一个
[fatherVC addChildViewController:VC];
[fatherVC.view addSubview:VC.view];
// 默认,第一个视图(你会发现,全程就这一个用了addSubview)
[VC didMoveToParentViewController:fatherVC];//确定关系建立
self.currentVC = VC;
}
}];
}
#pragma mark 选择按钮代理
-(void)getSelectButton:(NSInteger)chooseIndex{
UIViewController *VC = [self.controllers objectAtIndex:chooseIndex];
if (VC == self.currentVC) {
return;
}
else{
[self replaceController:self.currentVC newController:VC];
}
}
// 切换各个标签内容
- (void)replaceController:(UIViewController *)oldController newController:(UIViewController *)newController
{
/**
* 着重介绍一下它
* transitionFromViewController:toViewController:duration:options:animations:completion:
* fromViewController 当前显示在父视图控制器中的子视图控制器
* toViewController 将要显示的姿势图控制器
* duration 动画时间(这个属性,old friend 了 O(∩_∩)O)
* options 动画效果(渐变,从下往上等等,具体查看API)
* animations 转换过程中得动画
* completion 转换完成
*/
[self.fatherVC addChildViewController:newController];
[self.fatherVC transitionFromViewController:oldController toViewController:newController duration:0.2 options:UIViewAnimationOptionLayoutSubviews animations:nil completion:^(BOOL finished) {
if (finished) {
[newController didMoveToParentViewController:self.fatherVC];//确认关系
//移除上一个
[oldController willMoveToParentViewController:nil];
[oldController removeFromParentViewController];
self.currentVC = newController;
}
else{
self.currentVC = oldController;
}
}];
}
demo下载链接http://download.csdn.net/download/shenyingqiang/9080771