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 <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @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 <UIKit/UIKit.h> @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 <UIKit/UIKit.h> @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 <UIKit/UIKit.h> @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的功能.