自定义视图控制器切换(iOS)
在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
自定义视图控制器切换(iOS)的更多相关文章
- iOS 7 新特性:视图控制器切换API
本文转载至 http://blog.jobbole.com/51588/ 本文由 伯乐在线 - studentdeng 翻译自 Chris Eidhof.欢迎加入技术翻译小组.转载请参见文章末尾处的要 ...
- UI基础:UI程序执行顺序(UIApplicationMain()函数),自定义视图 分类: iOS学习-UI 2015-07-02 22:09 68人阅读 评论(0) 收藏
UI程序的一般执行顺序: 先进入main里面,执行函数UIApplicationMain(),通过该函数创建应用程序对象和指定其代理并实现监听,当执行函数UIApplicationMain()时还会做 ...
- 学习笔记:iOS 视图控制器(UIViewController)剖析
转自:http://www.cnblogs.com/martin1009/archive/2012/06/01/2531136.html 视图控制器在iOS编程中占据非常重要的位置,因此我们一定要掌握 ...
- Cocoa编程中视图控制器与视图类详解
iPhone编程规则是:一个窗口,多个视图.UIView是iPhone屏幕上很多控件的基础类.每个iPhone用户界面都是由显示在UIWindow(这其实也是个特殊的UIView)内的众多UIView ...
- iOS 视图控制器转场动画/页面切换效果/跳转动画 学习
一 学习 在 UINavigationController 中 push 和 pop 的转场效果 (基于iOS7 以上的转场方式) 经过学习了解到,重点分三块: (1)pushAnimation: ...
- iOS 在视图控制器里面判断 应用程序的前台 后台切换 UIViewController
1.时机 用户点击home 键 应用退到后台 再次点击进入前台 在UIViewController里面 控制器如何获取相关的事件? 2.需求 (1)NSTimer 在应用程序进入后台 10秒 ...
- iOS学习22之视图控制器
1.自定义视图 1> 概述 定义视图:系统标准UI之外,自己组合而出的新的视图. 定义视图的优点: iOS提供了很多UI组件,借助它们我们可以实现不同的功能.尽管如此,实际开发中,我们还需要 ...
- iOS,视图控制器相关(UIViewController)
1.视图控制器各个方法调用时机 2.选项卡(Tab Bar)和导航栏(Navigation Bar) 3.有无控制器的页面跳转 4.页面跳转隐藏底部选项卡 5.获取导航栏和状态栏高度,隐藏导航栏返回按 ...
- iOS 视图控制器转场详解
iOS 视图控制器转场详解 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...
随机推荐
- 《TCP/IP具体解释卷2:实现》笔记--4种不同类型的mbuf
mbuf的主要用途是保存子进程和网络接口间互相传递的用户数据.但mbuf也用于保存其它各种数据:源于目的地址.插口 选项等等. 以下介绍我们要遇到的四种类型的mbuf,它们根据在成员m_flag中填写 ...
- Impala与Hive的比較
1. Impala架构 Impala是Cloudera在受到Google的Dremel启示下开发的实时交互SQL大数据查询工具,Impala没有再使用缓慢的Hive+MapReduce批 ...
- Oracle 中的Pivoting Insert用法
1.标准Insert --单表单行插入 语法: INSERT INTO table [(column1,column2,...)] VALUE (value1,value2,...) ...
- [Spring入门学习笔记][静态资源]
遗留问题 在上一节课的作业中,我们一定遇到了一点问题——虽然将页面内容正确的返回给了浏览器,但是浏览器显示的样式却是不正确的,这是因为在HTML的\标签中我们这样引入了CSS资源: <link ...
- 【SQL学习笔记】排名开窗函数,聚合开窗函数(Over by)
处理一些分组后,该组按照某列排序后 ,取其中某条完整数据的问题. 或 按照其中不同列分组后的聚合 比如 sum,avg之类. MSDN上语法: Ranking Window Functions < ...
- studio中集成.so文件的两种方式
.so文件作为NDK的开发包,如果不进行依赖使用将会报错所以,需要.so的一定要配置 注:如果没有引用so文件,可能会在程序执行的时候加载类库失败,有类似如下的DEBUG提示: java.lan ...
- SQL重复记录查询的几种方法(转)
1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 代码如下: select * from people ) 2.删除表中多余的重复记录,重复记录是根据单个字段(people ...
- UVA 719 / POJ 1509 Glass Beads (最小表示法/后缀自动机)
题目大意: 给出一个长度为N的字符串,求其字典序最小的循环同构. N<=10W. 算法讨论: 算法一.最小表示法.定义题. 算法二.后缀自动机. Codes: #include <iost ...
- [uva11916] Emoogle Grid (离散对数)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Emoogle Grid You have to color an MxN ( ...
- (原)mkl用到的函数
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5585301.html 计算 $C=\alpha *A*B+\beta *C$: void cblas_ ...