自定义视图控制器切换(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 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...
随机推荐
- Cordova for android怎样在App中处理退出button事件
项目须要在HTML5 Android App中增加对返回键的处理,发现直接在Activity中加返回键处理代码不起作用,分析cordova源代码发现返回键已经被WebView处理掉了,所以仅仅能在js ...
- VS2008下编译boost_1_47_0
1,boost下载 如果不想自己编译,可下载http://boostpro.com/download/boost_1_47_setup.exe,安装后,程序会提供选项供下载已经编译好的库文件,基于 ...
- SQL:deferrable initially deferred
SQL> create table cust(id number,name varchar2(10));Table created SQL> alter table cust add co ...
- python -序列化
python中用于序列化的两个模块 json 用于[字符串]和[python基本数据类型]之间进行转换 pickle 用于[python特有的类型] 和 [python基本数据类型]间进行转换 Jso ...
- 微软TTS,Neospeech TTS 简单使用
今天搞了下微软的TTS,逛了好多网页.博客,拼拼凑凑搞了点东西吧. 首先添加类库调用,系统自带的system.speech using System.Speech.Synthesis; 然后就能调用方 ...
- weblogic开机启动脚本
1.在/home/bea/startBeaAll目录内创建一个startBeaAll.sh文件,加入如下内容(把相应目录与命令修改即可,红字部分为修改地方): #!/bin/sh echo " ...
- web跳转到自己的app
做个笔记 原文:http://blog.csdn.net/ba_jie/article/details/6884818 iPhone SDK可以把你的App和一个自定义的URL Scheme绑定.该U ...
- (转)eclipse 代码自动补全
转自:http://blog.csdn.net/yushuwai2010/article/details/11856129 一般默认情况下,Eclipse的代码提示功能是比MicrosoftVisua ...
- [Leetcode] Find the minimum in rotated sorted array
我在Github上新建了一个解答Leetcode问题的Project, 大家可以参考, 目前是Java 为主,里面有leetcode上的题目,解答,还有一些基本的单元测试,方便大家起步. 题目: Su ...
- static的用法解析
PHP中static变量的使用范围要更广一些,我们不仅可以在类,方法或变量前面添加static修饰符,我们甚至还能给函数内部变量添加static关键字.添加了static修饰符的变量即使在该函数执行完 ...