在iOS开发过程中,通常我们会使用UINavigationController,UITabbarController等苹果提供的视图控制器来切换我们的视图。在iOS5之前,如果要自定义容器视图控制器很麻烦,比如你要考虑到子视图的生命周期,当设备旋转时的情况等,好在iOS5中苹果提供了添加视图控制器(addChildViewController)等管理视图控制器的API,这样我们就能使用此API来自定义自己的视图控制器了,这篇文章只要介绍如何使用此API实现UITabbarController的基本功能。

开始

使用过UITabbarController的都知道,UITabbarController可以在多个UIViewController中切换,来显示多个界面,先来看一下层级关系:

TabbarController作为根视图,然后添加了一个ChildViewController,最后用户看到内容是ChildViewController的视图内容和底部的TabBar

首先我们新建一个新的工程,选择Single View Application,启用StoryBoard,将其默认的ViewController作为ContainerViewController,然后创建两个新的ViewController,分别作为两个childViewController,这样目录中就有这些文件:

我们先进入StoryBoard拖入两个UIButton,给两个button设置tag:

然后创建两个ViewController,这里我启用了xib,设置一下ViewController的背景色:

这里我一个设置了绿色,还有个设置了棕色,还分别在每个ViewController上添加了UILabel,用于区分

然后进入ContainerViewController.m,声明以下私有变量和方法:

@interface ContainerViewController () {
FirstViewController *_firstViewController;
SecondViewController *_secondViewController; NSMutableArray *_viewControllers;
}

- (IBAction)buttonTouched:(id)sender;


FirstViewController和SecondViewController是两个ChildViewController,_viewControllers则是保存ChildViewController的数组,再去StoryBoard关联下点击事件

在viewDidLoad中初始化:

- (void)viewDidLoad
{
[super viewDidLoad]; _viewControllers = [@[] mutableCopy];
_firstViewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
_secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; [_viewControllers addObject:_firstViewController];
[_viewControllers addObject:_secondViewController]; [self loadViewControllerAtIndex:];
}

实例化了两个ViewController,然后将两个ViewController添加至数组中

关键部分来了,loadViewControllerAtIndex用于切换视图控制器,以下是实现:

- (void)loadViewControllerAtIndex:(NSInteger)index {
NSInteger nextIndex = ;
if (index == ) {
nextIndex = ;
} else if (index == ) {
nextIndex = ;
} UIViewController *fromViewController = _viewControllers[nextIndex];// 获取当前viewController
UIViewController *toViewController = _viewControllers[index];// 获取将要切换的viewController

  //
if (self.childViewControllers.firstObject == toViewController) {
return;
} if (self.childViewControllers.count > ) {
self.view.userInteractionEnabled = NO;// 切换过程中禁用操作,等切换动画结束后恢复
[fromViewController willMoveToParentViewController:nil];// fromViewController将要移除
[self addChildViewController:toViewController];// 将toViewController添加至ContainerViewController

     // 设置view的frame
if (index == ) {
toViewController.view.frame = [self nextViewStartFrame];
} else {
toViewController.view.frame = [self preViewStartFrame];
}

     // 官方提供的切换动画API,在这里执行切换动画
[self transitionFromViewController:fromViewController toViewController:toViewController duration:0.25 options:UIViewAnimationOptionCurveEaseInOut animations:^{
         // 执行动画
if (index == ) {
fromViewController.view.frame = [self preViewStartFrame];
toViewController.view.frame = [self newViewStartFrame];
} else {
fromViewController.view.frame = [self nextViewStartFrame];
toViewController.view.frame = [self newViewStartFrame];
}
} completion:^(BOOL finished) {
       // 动画执行完毕,从父视图添加或移除层级关系
if (finished) {
[toViewController didMoveToParentViewController:self];
[fromViewController removeFromParentViewController];
self.view.userInteractionEnabled = YES;
}
}];
} else {
[self addChildViewController:toViewController];
[self.view addSubview:toViewController.view];
[toViewController didMoveToParentViewController:self];
}
}

- (CGRect)newViewStartFrame {

returnCGRectMake(0.0, 0.0, 320.0, 500.0);

}


- (CGRect)nextViewStartFrame {

returnCGRectMake(320.0, 0.0, 320.0, 500.0);

}


- (CGRect)preViewStartFrame {

returnCGRectMake(-320.0, 0.0, 320.0, 500.0);

}


这个函数用于切换视图,使用addChildViewController把要添加的ViewController添加至ContainerViewController,移除不需要显示的。添加一个ViewController有几个步骤:

1. [self addChildViewController:toViewController];  添加至当前viewController

2. [self.view addSubView:toViewController.view];   添加view至self.view中

3. [toViewController didMoveToParentViewController:self];  当添加完成后要调用此方法来告知已经移动到父视图控制器中

移除一个ViewController也有几个步骤:

1. [fromViewController willMoveToParentViewController:nil];  参数传入nil说明将要移除视图

2. [fromViewController.view removeFromSuperView];  从父视图中移除fromViewController.view

3. [fromViewController removeFromParentViewController];  将fromViewController从父视图层级中移除

想要添加和移除ViewController这几个步骤是必要的,但是这里由于使用了transitionFromViewController:toViewController:duration:options:animations:completion:这个方法,它会先将toViewController.view添加至superView,然后执行动画,所以省略了[self.view addSubView:toViewController.view]

这样切换函数就算完成了,然后我们实现按钮事件函数:

- (IBAction)buttonTouched:(id)sender {
if (((UIButton *)sender).tag == ) {
[self loadViewControllerAtIndex:];
} else {
[self loadViewControllerAtIndex:];
}
}

点击不同的按钮切换不同的界面,最后运行效果如下:

这里只是大致实现了下切换效果,在iOS7中新增的UIViewControllerContextTransitioning和UIViewControllerAnimatedTransitioning增强了对自定义的切换,这篇文章做了详细说明http://objccn.io/issue-12-3/

demo:https://github.com/mzds/ContainHolder/tree/master

参考:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html#//apple_ref/doc/uid/TP40007457-CH18-SW6

自定义视图控制器切换(iOS)的更多相关文章

  1. iOS 7 新特性:视图控制器切换API

    本文转载至 http://blog.jobbole.com/51588/ 本文由 伯乐在线 - studentdeng 翻译自 Chris Eidhof.欢迎加入技术翻译小组.转载请参见文章末尾处的要 ...

  2. UI基础:UI程序执行顺序(UIApplicationMain()函数),自定义视图 分类: iOS学习-UI 2015-07-02 22:09 68人阅读 评论(0) 收藏

    UI程序的一般执行顺序: 先进入main里面,执行函数UIApplicationMain(),通过该函数创建应用程序对象和指定其代理并实现监听,当执行函数UIApplicationMain()时还会做 ...

  3. 学习笔记:iOS 视图控制器(UIViewController)剖析

    转自:http://www.cnblogs.com/martin1009/archive/2012/06/01/2531136.html 视图控制器在iOS编程中占据非常重要的位置,因此我们一定要掌握 ...

  4. Cocoa编程中视图控制器与视图类详解

    iPhone编程规则是:一个窗口,多个视图.UIView是iPhone屏幕上很多控件的基础类.每个iPhone用户界面都是由显示在UIWindow(这其实也是个特殊的UIView)内的众多UIView ...

  5. iOS 视图控制器转场动画/页面切换效果/跳转动画 学习

    一 学习 在 UINavigationController 中 push 和 pop 的转场效果  (基于iOS7 以上的转场方式) 经过学习了解到,重点分三块: (1)pushAnimation:  ...

  6. iOS 在视图控制器里面判断 应用程序的前台 后台切换 UIViewController

    1.时机  用户点击home 键  应用退到后台 再次点击进入前台  在UIViewController里面 控制器如何获取相关的事件? 2.需求 (1)NSTimer   在应用程序进入后台 10秒 ...

  7. iOS学习22之视图控制器

    1.自定义视图 1> 概述   定义视图:系统标准UI之外,自己组合而出的新的视图. 定义视图的优点: iOS提供了很多UI组件,借助它们我们可以实现不同的功能.尽管如此,实际开发中,我们还需要 ...

  8. iOS,视图控制器相关(UIViewController)

    1.视图控制器各个方法调用时机 2.选项卡(Tab Bar)和导航栏(Navigation Bar) 3.有无控制器的页面跳转 4.页面跳转隐藏底部选项卡 5.获取导航栏和状态栏高度,隐藏导航栏返回按 ...

  9. iOS 视图控制器转场详解

    iOS 视图控制器转场详解 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...

随机推荐

  1. 一个用 Cumulative Penalty 培训 L1 正规 Log-linear 型号随机梯度下降

      Log-Linear 模型(也叫做最大熵模型)是 NLP 领域中使用最为广泛的模型之中的一个.其训练常採用最大似然准则.且为防止过拟合,往往在目标函数中增加(能够产生稀疏性的) L1 正则.但对于 ...

  2. JS中面向对象的,对象理解、构造函数、原型、原型链

    6.1 理解对象 6.1.1 对象属性类型 ECMS属性有两种类型:数据属性和访问器属性 1 数据属性 [[configurable]] 表示能否通过Delete 删除属性从而从新定义属性,能否修改属 ...

  3. asp.net 追加文本(追加写入记事本)

    代码: string path = Server.MapPath("/Log/Log.txt"); if (File.Exists(path)) { using (StreamWr ...

  4. 调用[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad判断设备

    将模拟器改为Ipad时,调用[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad判断设备是否为Ipad,但程序并 ...

  5. C#获取QQ旋风的下载记录

    /* * 用户:从前的我 * 日期:2015/8/26 */ using System; using System.IO; namespace GetXf { class Program { publ ...

  6. jQuery常用选择器汇总

    一.基本选择器 <body> <div> <div id="div1"> aaaaaaaaaaa</div> <div cla ...

  7. https://github.com/aptana/studio3/releases aptana

    https://github.com/aptana/studio3/releases  aptana

  8. django框架介绍

    主要内容 1.        Django框架发展 2.        Django架构,MTV模式 3.        开发流程 4.        开发实例——Poll python下各种框架 一 ...

  9. HDU 4970 Killing Monsters

    开始以为是线段树,算了一下复杂度也觉得能过...但是这题貌似卡了线段树... 具体做法: 对每一个塔,记录attack[l]+=d,attack[r+1]-=d;这样对于每个block,受到的伤害就是 ...

  10. jsp执行数据库查询并分页

    需求: 有一批企业的基本信息需要展示出来,要求一级页以列表形式展示企业清单,点击公司名称后进入二级页面,二级页面展示企业简介和几张图片. 实现效果: 开发环境: Win7,Eclipse,Mysql ...