addChildViewController
If the new child view controller is already the child of a container view controller, it is removed from that container before being added.This method is only intended to be called by an implementation of a custom container view controller. If you override this method, you must call super in your implementation.如果这个子 view controller 已经被添加到了一个容器 controller 当中,那在它被添加进新的容器controller之前会从旧的容器中移除.
这个方法只能被用来实现一个自定义的容器controller添加子controller.如果你重写了这个方法,你必须调用super方法.
使用源码:
AppDelegate.h + AppDelegate.m
#import@interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window;@end
#import "AppDelegate.h"#import "RootViewController.h"@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // 加载根视图控制器 self.window.rootViewController = [RootViewController new]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}@end
RootViewController.h + RootViewController.m
#import@interface RootViewController : UIViewController@end
#import "RootViewController.h"#import "FirstViewController.h"#import "SecondViewController.h"// 获取当前屏幕尺寸#define SCR_HEIGHT [UIScreen mainScreen].bounds.size.height// 设置按钮高度static CGFloat downLenth = 40.f;// 标示button的枚举值typedef enum{ BUTTON_1 = 0x11, BUTTON_2,} EFlags;@interface RootViewController (){ UIViewController *currentVC; }@property (nonatomic, strong) UIView *showArea; // 加载子controller的view@property (nonatomic, strong) FirstViewController *firstVC; // 子controller@property (nonatomic, strong) SecondViewController *secondVC; // 子controller@end@implementation RootViewController- (void)viewDidLoad{ [super viewDidLoad]; // 初始化控制器 [self controllersInit]; // 初始化要展示的区域 [self showAreaInit]; // 初始化按钮 [self buttonsInit];}#pragma mark - 初始化控制器- (void)controllersInit{ // 初始化两个控制器并作为root控制器的subController _firstVC = [FirstViewController new]; [self addChildViewController:_firstVC]; [_firstVC didMoveToParentViewController:self]; _secondVC = [SecondViewController new]; [self addChildViewController:_secondVC]; [_secondVC didMoveToParentViewController:self];}#pragma mark - 初始化要展示的区域- (void)showAreaInit{ // 初始化要展示的区域 self.showArea = [UIView new]; self.showArea.frame = CGRectMake(0, 0, 320, SCR_HEIGHT - downLenth - 10); self.showArea.layer.masksToBounds = YES; [self.view addSubview:_showArea]; // 将第一个控制器的view添加进来展示 [self.showArea addSubview:_firstVC.view]; currentVC = _firstVC;}#pragma mark - 初始化按钮以及按钮事件- (void)buttonsInit{ UIButton *firstVCButton = [UIButton new]; [self.view addSubview:firstVCButton]; firstVCButton.backgroundColor = [UIColor redColor]; firstVCButton.tag = BUTTON_1; firstVCButton.frame = CGRectMake(0, SCR_HEIGHT - downLenth, 320 / 2, downLenth); [firstVCButton addTarget:self action:@selector(buttonsEvent:) forControlEvents:UIControlEventTouchUpInside]; UIButton *secondVCButton = [UIButton new]; [self.view addSubview:secondVCButton]; secondVCButton.backgroundColor = [UIColor yellowColor]; secondVCButton.tag = BUTTON_2; secondVCButton.frame = CGRectMake(320 / 2, SCR_HEIGHT - downLenth, 320 / 2, downLenth); [secondVCButton addTarget:self action:@selector(buttonsEvent:) forControlEvents:UIControlEventTouchUpInside];}- (void)buttonsEvent:(UIButton *)button{ if (button.tag == BUTTON_1) { if (currentVC == _firstVC) { return; } [self transitionFromViewController:currentVC toViewController:_firstVC duration:0 options:UIViewAnimationOptionTransitionNone animations:^{ } completion:^(BOOL finished) { currentVC = _firstVC; }]; } if (button.tag == BUTTON_2) { if (currentVC == _secondVC) { return; } [self transitionFromViewController:currentVC toViewController:_secondVC duration:0 options:UIViewAnimationOptionTransitionNone animations:^{ } completion:^(BOOL finished) { currentVC = _secondVC; }]; }}@end
FirstViewController.h + FirstViewController.m
#import@interface FristViewController : UIViewController@end
#import "FristViewController.h"@interface FristViewController ()@end@implementation FristViewController- (void)viewDidLoad{ [super viewDidLoad]; NSLog(@"FirstViewController viewDidLoad");}- (void)viewWillAppear:(BOOL)animated{ NSLog(@"FirstViewController viewWillAppear");}- (void)viewDidAppear:(BOOL)animated{ NSLog(@"FirstViewController viewDidAppear");}- (void)viewWillDisappear:(BOOL)animated{ NSLog(@"FirstViewController viewWillDisappear");}- (void)viewDidDisappear:(BOOL)animated{ NSLog(@"FirstViewController viewDidDisappear");}@end
SecondViewController.h + SecondViewController.m
#import@interface SecondViewController : UIViewController@end
#import "SecondViewController.h"@interface SecondViewController ()@end@implementation SecondViewController- (void)viewDidLoad{ [super viewDidLoad]; NSLog(@"SecondViewController viewDidLoad");}- (void)viewWillAppear:(BOOL)animated{ NSLog(@"SecondViewController viewWillAppear");}- (void)viewDidAppear:(BOOL)animated{ NSLog(@"SecondViewController viewDidAppear");}- (void)viewWillDisappear:(BOOL)animated{ NSLog(@"SecondViewController viewWillDisappear");}- (void)viewDidDisappear:(BOOL)animated{ NSLog(@"SecondViewController viewDidDisappear");}@end
需要注意的地方:
1. 容器controller最好定义一个专门用来展示子controller相关view的区域,如例子中的,其中,masksToBounds很重要,要不然,整个controller都会被展示出来的.
self.showArea = [UIView new]; self.showArea.frame = CGRectMake(0, 0, 320, SCR_HEIGHT - downLenth - 10); self.showArea.layer.masksToBounds = YES; [self.view addSubview:_showArea]; [self.showArea addSubview:_firstVC.view];
2. 调用完addChildViewController之后还需要调用didMoveToParentViewController,官方文档里面有说明.
3. 为什么在点击一个按钮切换控制器的时候,showArea什么都不用设置,为何还能显示出变化呢?
其实这一点我也没弄明白为何呢.
4. 这个与UITabbarController的功能类似,都有懒加载功能,实际上可以用来当做模拟UITabbarController使用,具备更高自由度的定制Tabbar的功能.