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的功能.