自定义视图控制器切换(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 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...
随机推荐
- http://blog.csdn.net/luoshengyang/article/details/6651971
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6651971 在Android系统中,提供了独特 ...
- MSN在Win7下80072f0d错误解决
近期电脑(笔记本联想 K41A)显卡出了点问题(该显卡一周前刚换的新的,竟然不到一周又出问题了,联想的质量真的...),在xp下电脑根本进不了操作系统,不断重新启动(可能驱动.系统垃圾太多有关),于是 ...
- sqlite3安装
SQLite命令行程序(CLP)是开始使用SQLite的最好选择,按照如下步骤获取CLP: 1).打开浏览器进入SQLite主页,www.sqlite.org. 2).单击页面顶部的下载链接(Down ...
- ScriptManager局部刷新
ScriptManager和UpdatePanel控件联合使用可以实现页面异步局部更新的效果.其中的UpdatePanel就是设置页面中异步局部更新区域,它必须依赖于ScriptManager存在,因 ...
- django防止表单数据重复提交
思路: 在Asp.net中存在Page.IsPostback的方法,所以对django中表单提交数据的重复提交的数据采用相似方法实现,即在页面第一次访问时,即访问方法为GET方法在view中 ...
- C++、GDAL创建shapefile,并向矢量文件中添加网格
//总体来说这个过程就是构建数据源->构建层->构建要素->构建形状->关闭数据源. //要包含的GDAL头文件 #include <gdal_priv.h> #i ...
- Tomcat 服务器的端口号的修改
在系统中找到Tomcat安装目录下的conf文件夹下的servlet.xml文件. (1)在servlet.xml文件中找到以下代码: <connector port="8080&qu ...
- 【Nutch2.2.1基础教程之2.2】集成Nutch/Hbase/Solr构建搜索引擎之二:内容分析
请先参见"集成Nutch/Hbase/Solr构建搜索引擎之一:安装及运行",搭建测试环境 http://blog.csdn.net/jediael_lu/article/deta ...
- Python中for\while的用法
代码示例 board = [] for i in range(5): board.append(i) print board board = [] i = 0 while i < 5: boar ...
- 宽带连接工具[bat]
功能概述: 本工具使用批处理编写,提供自动判断网络状态以决定断开或是连上网络,本月已用宽带时长,到月初自动清零.提供联网日志功能,可以记录下所有的连接或断开网络记录.如果连接失败,自动提示输入密码,特 ...