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

目录
相关文章
|
JavaScript 开发者
组件切换-应用切换动画和 mode 方式|学习笔记
快速学习组件切换-应用切换动画和 mode 方式
124 0
组件切换-应用切换动画和 mode 方式|学习笔记
ViewPager如何区分自动切换和手势滑动切换
ViewPager是一个很常见的组件,不仅支持收拾滑动切换页面,我们还可以通过`viewPager.setCurrentItem(index)`来切换到指定的页面,那么他们如何区分呢? 我们知道ViewPager可以添加`ViewPager.OnPageChangeListener`监听器,可以监听切换的状态。通过观察`ViewPager.OnPageChangeListener#onPageScrollStateChanged(int state)`方法中state的输出,发现了手势切换和自动切换的规律。
|
Android开发
Android软键盘状态的切换及其强制隐藏
MainActivity如下:package cc.c; import android.os.Bundle; import android.view.
851 0
|
前端开发 API Android开发
一道面试题:ViewModel为什么横竖屏切换时不销毁?
如今Android面试中经常问及Jetpack相关问题,很多候选人往往知道如何使用但不知道原理。原理不清虽不影响API的使用,但也正因为如此,如果能对源码有一定了解,也许可以脱颖而出得到加分。
407 0
|
C# Windows 容器
C#实现多个子窗体切换效果
C#实现多个子窗体切换效果
1256 0
C#实现多个子窗体切换效果
自定义状态切换按钮
最近在做一个项目,一个界面的按钮UI给画成了这样(默认状态是蓝色的然后触摸后变成灰色的) UI效果 然后本着给低版本系统APP适配的职业素养(其实是不想画这种按钮),想让UI兄弟给将图标改成整个按钮效果的图片,可是。
974 0