iOS早在iOS5的时候为了解耦、更加清晰的处理页面View的逻辑,UIViewController
提供了addChildViewController
方法,将ViewController
作为容器处理视图控制器的切换,将比较复杂的UI使用子ViewController
来管理。
iOS5.0
之前只能在ViewController
的view
中不断的通过addSubView
添加subView
到VC
的view
视图层级中。这样使得主ViewController
中的内容越来越混乱,代码越来越多,subView
的管理越来越困难。
iOS5.0
之后按照MVC
的原则,每个ViewController
只需要管理一个view视图层次结构,因此我们可以使用childViewController
来拆分开发中比较复杂的View
。并且此时的childViewController拥有了与父ViewController同步的声明周期。
项目中使用:
在我们项目的APP首页的实现中使用到了,首页内容展示位推荐分类菜单,以及每个菜单下的内容展示,不同的分类下的内容view
展示的UI多样化。
相关方法:
///子视图控制器数组
@property(nonatomic,readonly) NSArray *childViewControllers
///向父VC中添加子VC
- (void)addChildViewController:(UIViewController *)childController
///将子VC从父VC中移除
- (void) removeFromParentViewController
///fromViewController 当前显示在父视图控制器中的子视图控制器
///toViewController 将要显示的姿势图控制器
///duration 动画时间
/// options 动画效果(渐变,从下往上等等,具体查看API)
///animations 转换过程中得动画
///completion 转换完成
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion
///当向父VC添加子VC之后,该方法会自动调用;
- (void)willMoveToParentViewController:(UIViewController *)parent
///从父VC移除子VC之后,该方法会自动调用
- (void)didMoveToParentViewController:(UIViewController *)parent
如何使用?:
- 如果在view上添加的只是简单的控件的话,那么使用addSubView添加到父ViewController上;
- 如果子视图是比较复杂的视图集合,功能丰富,就选择使用
addChildViewController
来添加新的子ViewController
,但也需要通过addSubview
将子ViewController
的view
添加到父视图的视图层级中; - iOS5之后使用
addChildViewController
时的原则,我们在使用addSubview的时候,同时调用addChildViewController
方法将subView对应的viewController
也加到当前viewController
的管理中; - 对于那些不需要显示的
subView
,只需通过addChildViewController
把subVC
添加到父控制器中,需要显示时再调用transitionFromViewController
方法将其显示出来; - 当收到系统的
Memory Warning
的时候,系统也会自动把当前没有显示的subview
销毁掉 掉,以节省内存; - 优点:
- 使页面逻辑更加清晰明了,遵循MVC模式,每个View对应相应的ViewController;
- 当存在不需显示的view时,将不会被加载,减少内尺使用;
- 当收到内存警告时,会将没有加载出的view率先释放,优化了程序的内存释放机制;
系统方法解释:
- addChildViewController
[A父视图控制器 addChildViewController:B子视图控制器]在视图控制器A中添加了子视图控制器B.调用这个方法时如果子视图控制器已经有父视图控制器了,那么调用该方法会先把子视图控制器从之前的父视图控制器中移除,然后再添加到当前的视图控制器上作为子视图控制器。
注意:调用addChildViewController后会自动调用willMoveToParentViewController:superVC方法;
- removeFromParentViewController
将子视图控制器从父视图控制器中移除,移除之后将自动调用
didMoveToParentViewController
注意:调用removeFromParentViewControlle后会调用didMoveToParentViewController:nil方法
- willMoveToParentViewController
当一个视图控制器从视图控制器容器中被添加或者被删除之前,该方法被调用parent:父视图控制器,如果没有父视图控制器,将为nil;当调用
removeFromParentViewController
方法是必须先手动调用该方法,且parent参数为nil。
- didMoveToParentViewController
当从一个视图控制容器中添加或者移除viewController后,该方法被调用;当调用
addChildViewController
方法时必须手动调用该方法,且parent参数为父控制器。
代码展示:
- 添加子VC
//自动调用,可以省略
//[childVC willMoveToParentViewController: superVC];
[superVC addChildViewController:childVC];
[superVC.view addSubview:childVC.view];
[childVC didMoveToParentViewController:superVC];
- 删除子VC
[childVC willMoveToParentViewController];
[childVC removeFromParentViewController];
//自动调用,可以省略
//[childVC didMoveToParentViewController:nil];
- 切换子VC
[self addChildViewController:newController];
[self transitionFromViewController:oldController toViewController:newController duration:1.5f options:UIViewAnimationOptionCurveEaseOut animations:^{
} completion:^(BOOL finished) {
if (finished) {
[newController didMoveToParentViewController:self];
[oldController willMoveToParentViewController:nil];
[oldController removeFromParentViewController];
self.currentVC = newController;
}
else{
self.currentVC = oldController;
}
}];
总结:
-
addChildViewController
向父视图控制器中添加子视图控制器时,添加之后自动调用willMoveToParentViewController
,需要手动调用didMoveToParentViewController
; -
removeFromParentViewController
将子视图控制器从父视图控制器中移除,移除之后自动调用didMoveToParentViewController: nil
参数为nil
,需要在移除前手动调用willMoveToParentViewController
; -
transitionFromViewController:toViewController
在调用这个方法之前先调用[fromViewController willMoveToParentViewController:nil]
然后在completion
后调用[toViewController didMoveToParentViewController:self]
方法; - 在切换子视图控制器显示的时候需要保证切换的子视图控制器已经被添加到父视图控制器中;
- 当某个子视图控制器将从父视图控制器中删除时,
parent
参数为nil,即:[将被删除的VC willMoveToParentViewController:nil]
; - 当某个子试图控制器将加入到父视图控制器时,
parent
参数为父视图控制器,即:[将被加入的VC didMoveToParentViewController:superVC]
;