使用addChildViewController手动控制UIViewController的切换
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的功能.