初学 iOS,本文翻译了一些 iOS 官网上的 UIViewController 的知识点,如有不到位或不正确的地方,还请指正:

本文所介绍的内容的目标:

  • 理解content view controllers 和 container view controllers

  • 知道如何实现自定义view controller containers 以及 何时使用view controller containers

  • 在iOS5操作系统下使用UIPageViewController

  • 分享一些新的API和使用技巧

这是一个UIViewController

我们为什么要使用视图控制器(View Controllers)?

两个原因

  1. 使用它能够做出更高品质的APP
  2. 它们可被继承

视图控制器(基础知识)

设计模式

  • 它们是MVC中的C

  • 它们管理着“整个屏幕里显示的内容”

  • 它们通常和它们的对象模型打包在一起

使用系统视图控制器(System View Controllers)

系统视图控制器通包括以下5种

  • TWTweetComposeViewController

  • UIImagePickerController

  • EKEventViewController

  • MFMailComposeViewController

  • MPMediaPickerController

设计模式

  • 它们是MVC中的C

  • 它们管理着“整个屏幕里显示的内容”

  • 它们通常和它们的对象模型打包在一起

  • 你的应用程序可以再各个视图控制器之间移动

    (Your application flows between view controllers)

  • 它们管理“整个屏幕里显示的内容”?

  • 它们看起来有很灵活的边界

  • 他们管理这各自独立的“内容单元”

Table view controller: 表视图控制器

Detail controller: 详细控制器

SVC:SSL VPN Client

根视图控制器真的可以管理“整个屏幕里显示的内容”么?

  1. window.rootViewController= RootViewController

自定义视图控制器

  • 子类的UIViewController
  • 视图控制器与视图层关联
  • 重写所选择的API
  • 在应用程序中添加逻辑
  • 配置tango执行应用程序

Appearance callbacks

  1. (void)viewWillAppear:
  2. (void)viewDidAppear:
  3. (void)viewWillDisappear:
  4. (void)viewDidDisappear:

Rotation callbacks

  1. (void)viewWillRotateToInterfaceOrientation:duration:
  2. (void)viewWillAnimateRotationToInterfaceOrientation:
  3. (void)viewDidRotateFromInterfaceOrientation:

也许在iPhone上很少要关心的屏幕旋转问题的,但是大屏幕的iPad上就不同了,很多时候你需要关心横竖屏。rotation callbacks 一般情况下只需要关心三个方法 :

willRotateToInterfaceOrientation:duration:在旋转开始前,此方法会被调用;

willAnimateRotationToInterfaceOrientation:duration: 此方法的调用在旋转动画block的内部,也就是说在此方法中的代码会作为旋转animation block的一部分;

didRotateFromInterfaceOrientation:此方法会在旋转结束时被调用。而作为view controller container 就要肩负起旋转的决策以及旋转的callbacks的传递的责任。

视图控制器(基础知识)

总结

  • 视图控制器仅仅只是控制器 —— 是MVC中的C

  • 视图控制器管理视图层次结构 —— 而非单一的视图

  • 视图控制器通常是自包含的(可重复使用)

  • 视图控制器连接并支持通用的iOS应用程序流

路线图

了解视图控制器容器

  • 视图控制器和视图层次

  • 视图控制器互相连接的三种方式

  • 设计自定义容器控制器

  • 探讨如何新增和修改API

视图控制器

两个层次的故事

蓝色:视图颜色

蓝色箭头:子视图关系

金色: 视图控制器颜色

灰色箭头:父视图控制器关系

相对于内容的容器

层次关系



视图控制器容器

层次关系

视图控制器容器

层次关系

  • 你应该知道些什么?

    容器控制器是负责 父/子 关系的

视图控制器容器

API和控制器层次

API和控制器层次

Container View Controller

容器视图控制器包含其他视图控制器所拥有的内容。也就是说一个View Controller显示的某部分内容属于另一个View Controller,那么这个View Controller就是一个Container.

iOS 5.0 开始支持Custom Container View Controller,开放了用于构建自定义Container的接口。如果你想创建一个自己的Container,那么有一些概念还得弄清楚。Container的主要职责就是管理一个或多个Child View Controller的展示的生命周期,需要传递显示以及旋转相关的回调。

  • UITableViewController

    很多应用程序显示表格数据。因此,iOS提供了一个专门用来管理表格数据的内建的UIViewController类的子类。UITableViewController 管理一个表格视图并支持很多标准表格相关的行为,比如选择(selection)管理,行编辑,以及表格配置。这些额外的支持减少了你创建和初始化一个基于表格界面必须编写的代码总量。你还可以子类化UITableViewController来添加其它自定义行为。

  • Recipe Controller

    食谱控制器

显示或者旋转的回调的触发的源头来自于window,一个app首先有一个主window,初始化的时候需要给这个主window指定一个rootViewController,window会将显示相关的回调(viewWillAppear:, viewWillDisappear:, viewDidAppear:, or viewDidDisappear: )以及旋转相关的回调(willRotateToInterfaceOrientation:duration: ,willAnimateRotationToInterfaceOrientation:duration:, didRotateFromInterfaceOrientation:)传递给rootViewController。rootViewController需要再将这些callbacks的调用传递给它的Child View Controllers。

视图控制器容器

API和控制器层次

  • 添加和删除子控制器
  1. (void)addChildViewController:(UIViewController *)childController; (void)removeFromParentViewController;
  • 访问子控制器
  1. @property(nonatomic,readonly) NSArray *childViewControllers;
  • 回调
  1. (void)willMoveToParentViewController:(UIViewController *)parent; (void)didMoveToParentViewController:(UIViewController *)parent;

视图控制器容器

层次关系

  • 你应该知道些什么?

    容器控制器是负责 父/子 关系的

    有一致和不一致的层次结构

视图控制器容器

不一致的层次结构

UIViewControllerHierarchyInconsistencyException

为什么会这么糟糕?

视图控制器容器

层次关系

  • 你应该知道些什么?

    容器控制器是负责 父/子 关系的

    有一致和不一致的层次结构

    这时,其实出现了回调

  1. [self addChildViewController:note];
  2. // Transition to note controller with a flip transition which adds
  3. // tne note view to the window hierarchy and removes the recipe view.
  4. [self transitionFromViewController:recipe
  5. toViewController:note
  6. duration:.5
  7. options:UIViewAnimationOptionTransitionFlipFromRight
  8. animations:nil
  9. completion:^(BOOL finished) {
  10. [note didMoveToParentViewController:self];
  11. }];
  • viewWillAppear:

    该视图添加到 windows 的视图层次结构之前调用

    在 [vc.view layoutSubviews](if necessary)之前调用

  • viewDidAppear:

    该视图添加到视图层次结构之后调用

    在 [vc.view layoutSubviews](if necessary)之后调用

  • viewWillDisappear:

    该视图从 windows 的视图层次结构移除之前调用

  • viewDidDisappear:

    该视图从 windows 的视图层次结构移除之后调用

  1. [self addChildViewController:note];
  2. // Transition to note controller with a flip transition which adds
  3. // tne note view to the window hierarchy and removes the recipe view.
  4. [self transitionFromViewController:recipe
  5. toViewController:note
  6. duration:.5
  7. options:UIViewAnimationOptionTransitionFlipFromRight
  8. animations:nil
  9. completion:^(BOOL finished) {
  10. [note didMoveToParentViewController:self];
  11. }];

视图控制器容器

API和控制器层次

  • 子视图控制器之间的转换
  1. - (void)transitionFromViewController:(UIViewController *) fromVC
  2. toViewController:(UIViewController *)toVC
  3. duration:(NSTimeInterval)duration
  4. options:(UIViewAnimationOptions)options
  5. animations:(void (^)(void))animations
  6. completion:(void (^)(BOOL finished))completion;
  • 布局视图层次结构
  1. - (void)viewWillLayoutSubviews
  2. - (void)viewDidLayoutSubviews

连接

流 — —打开和关闭屏幕时获取视图控制器

连接视图控制器

  • 通过container controllers(容器控制器)

  • 通过presentation(呈现) 和 dismissal (解散)

  • 通过直接视图操作

Containers(容器)

  1. - (void)pushViewController:
  2. animated:
  3. - (void)popViewControllerAnimated:

Presentation and dismissal

  1. - (void) presentModalViewController:
  2. animated:
  3. - (void) dismissModalViewControllerAnimated:

  1. - (void)presentViewController: (UIViewController *)vc
  2. animated: (BOOL)animated
  3. completion: (void (^)(void))completion;
  4. - (void)dismissViewControllerAnimated:(BOOL)animated
  5. completion: (void (^)(void))completion;

  1. - (UIViewController *)parentViewController;
  2. - (UIViewController *)presentingViewController;

视图操作

[root.someView addSubview: vc.view]

[rootVC addChildViewController: vc]

视图控制器容器

inception(启动)

  • 你会在什么时候考虑创建一个自定义视图控制器容器?

    Aesthetics(考虑到美观)

    自定义应用程序流

    您的应用程序直接处理视图层次结构

inception(启动)仅在iPad上

  1. @protocol UISplitViewControllerDelegate
  2. ...
  3. // Returns YES if a view controller should be hidden by
  4. // the split view controller in a given orientation.
  5. // (This method is only called on the leftmost view controller
  6. // and only discriminates portrait from landscape.)
  7. - (BOOL)splitViewController: (UISplitViewController*)svc
  8. shouldHideViewController:(UIViewController *)vc
  9. inOrientation:(UIInterfaceOrientation)orientation;
  10. @end

设计一个新的应用程序流

为修正一个食谱应用创建一个应用程序流

Container View Controller Demo

视图控制器容器

演示亮点 — — 容器的移动

  1. - (IBAction)flipToNote
  2. {
  3. if(...) {
  4. ...
  5. [self addChildViewController:_noteController];
  6. [self transitionFromViewController:_contentController
  7. toViewController:_noteController duration:.5
  8. options:UIViewAnimationOptionTransitionFlipFromRight
  9. animations:nil
  10. completion:^(BOOL finished) {
  11. _flipNoteButton.title = @"Hide Note";
  12. _flipNoteButton.action = @selector(flipFromNote);
  13. [_noteController didMoveToParentViewController:self];
  14. }];
  15. }
  16. }
  1. - (IBAction)flipFromNote
  2. {
  3. if(_isNoteBeingShown) {
  4. [_noteController willMoveToParentViewController:nil];
  5. [self transitionFromViewController:_noteController
  6. toViewController:_contentController duration:0.5
  7. options:UIViewAnimationOptionTransitionFlipFromLeft
  8. animations:nil
  9. completion:^(BOOL finished) {
  10. _flipNoteButton.title = @"Show Note";
  11. _flipNoteButton.action = @selector(flipToNote);
  12. [_noteController removeFromParentViewController];
  13. _isNoteBeingShown = NO;
  14. }];
  15. }
  16. }

Moving in and out of containers

  1. - (void)viewDidAppear:(BOOL)animated
  2. {
  3. [super viewDidAppear:animated];
  4. if(![self isMovingToParentViewController]) {
  5. [[self parentViewController] updateSelectionForListOfContentIdentifiersIfNecessary];
  6. }
  7. }

inception(启动)

  1. - (BOOL)isMovingToParentViewController; // Used in appearance callbacks
  2. - (BOOL)isMovingFromParentViewController; // Used in disappearance callbacks
  3. - (BOOL)isBeingPresented;
  4. - (BOOL)isBeingDismissed;
  1. - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers;

  1. - (IBAction)flipToNote
  2. {
  3. if(...) {
  4. ...
  5. [self addChildViewController:_noteController];
  6. [_noteController viewWillAppear: YES];
  7. // Some fancy animation that culminates in the view swap
  8. // E.g [[_contentController.view superview] addSubview:_noteController.view];
  9. ...
  10. // Finally this is usually called in a completion handler
  11. // after the animation completes
  12. [_noteController viewDidAppear: YES];
  13. [_noteController didMoveToParentViewController:self];
  14. }
  15. }

容器视图控制器示例

为修正一个食谱应用创建一个应用程序流

演示亮点 — — 定义演示文稿上下文

  1. - (IBAction)emailContent
  2. {
  3. UIViewController *presenter= _isNoteBeingShown ? _noteController:
  4. _contentController;
  5. ...
  6. mailController.modalPresentationStyle = UIModalPresentationCurrentContext;
  7. if(_contentController && [MFMailComposeViewController canSendMail]) {
  8. ...
  9. data = [_contentProvider dataForContentIdentifier:self.contentControllerIdentifier
  10. mimeType:&mimeType];
  11. note = [_contentProvider noteForContentIdentifier:self.contentControllerIdentifier];
  12. ...
  13. [presenter presentViewController:mailController
  14. animated:YES
  15. completion:^{[mailController release];}];
  16. }
  17. }

  1. mc.modalPresentationStyle = UIModalPresentationCurrentContext;
  2. [rb presentViewController:mailController
  3. animated:YES
  4. completion:^{...}];

  1. mc.modalPresentationStyle = UIModalPresentationCurrentContext;
  2. [note presentViewController:mailController
  3. animated:YES
  4. completion:^{...}

  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |
  5. UIViewAutoresizingFlexibleHeight;
  6. self.definesPresentationContext = YES;
  7. ...
  8. }
  1. @property(nonatomic,assign) BOOL definesPresentationContext;
  2. // A controller that defines the presentation context can also
  3. // specify the modal transition style if this property is true.
  4. @property(nonatomic,assign) BOOL providesPresentationContextTransitionStyle;

视图控制器容器

总结

  • 尽可能利用现有的容器

    视图控制器可以管理多个视图

    不是每个视图都需要一个视图控制器

  • 当需要时,创建自定义视图控制器容器

    定义新的应用程序或实现

    而不是直接视图操作(这将创造出具有前瞻性的应用)

  • 该 API 很简单

    但理解你的层次结构

UIPageViewController

导航与视图之间的页面卷曲过渡

UIPageViewController

一个容器视图控制器

  • 管理子视图控制器的当前内容

  • 展示一个已准备的应用程序流程

Initialization(初始化)

  1. - initWithTransitionStyle:
  2. navigationOrientation:
  3. options:
  1. UIPageViewController *myPVC = [[UIPageViewController alloc]
  2. initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
  3. navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
  4. options:[NSDictionary dictionaryWithObjectsAndKeys:
  5. [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMid],
  6. UIPageViewControllerOptionSpineLocationKey]]

初始视图控制器

  1. - setViewControllers:
  2. direction:
  3. animated:
  4. completion:
  1. [myPVC setViewControllers:[NSArray arrayWithObjects:firstVC, secondVC, nil]
  2. direction:UIPageViewControllerNavigationDirectionForward
  3. animated:NO
  4. completion:nil];

编程导航

  1. [myPVC setViewControllers:[NSArray arrayWithObjects:thirdVC, fourthVC, nil]
  2. direction:UIPageViewControllerNavigationDirectionForward
  3. animated: NO
  4. completion:nil]
  1. YES
  2. ^(BOOL finished) {
  3. NSLog(@"Page curl completed.");
  4. }];
  1. [myPVC setViewControllers:[NSArray arrayWithObjects:thirdVC, fourthVC, nil]
  2. direction:UIPageViewControllerNavigationDirectionForward
  3. animated:
  4. completion:
  5. YES
  6. ^(BOOL finished) {
  7. NSLog(@"Page curl completed.");
  8. }];

交互-用户驱动导航

Demo 总结

  • 接下来我们知道

    1. 初始化页面视图控制器与过渡样式,导航定位和任何选项 (spine location)
    2. 设置初始视图控制器 (和驱动编程导航)
    3. 通过设置数据源允许用户驱动导航
  • 我们从中学到什么:

    1. 通过放置手势识别器自定义手势区
    2. 在旋转和拖拽过程中改变spine location
  • 理解内容和容器视图控制器之间的区别

  • 使用自定义视图控制器容器...

    。。。定义新的应用程序或looks

    。。。代替直接视图操作

  • 尽可能利用现有的容器

    UINavigationController, UITabBarController, UISplitViewController, etc.

    新的容器视图控制器, UIPageViewController

OneAPM Mobile Insight,监控网络请求及网络错误,提升用户留存。访问 OneAPM 官方网站感受更多应用性能优化体验,想阅读更多技术文章,请访问 OneAPM 官方技术博客

本文转自 OneAPM 官方博客

移动开发:初学 iOS-UIViewController 心得的更多相关文章

  1. [Android开发学iOS系列] iOS写UI的几种方式

    [Android开发学iOS系列] iOS写UI的几种方式 作为一个现代化的平台, iOS的发展也经历了好几个时代. 本文讲讲iOS写UI的几种主要方式和各自的特点. iOS写UI的方式 在iOS中写 ...

  2. 【转载国外好文】代工开发一个iOS应用没有那么容易

    导读:这是来自新加坡的 iOS 开发者 Kent Nguyen 发表在1月底的一篇博文.这篇吐槽文在 iOS 开发圈子里流传甚广,从原文150多个评论就可见一斑,现翻译如下. 让我们开门见山吧:做一个 ...

  3. iOS UIViewController 和 nib 相关的3个方法

    iOS UIViewController 的 awakeFromNib 以及 - (id)initWithCoder:(NSCoder *)aDecoder 和 - (instancetype)ini ...

  4. Safari 前端开发调试 iOS 完美解决方案

    转http://www.2cto.com/kf/201403/283404.html afari 前端开发调试 iOS 完美解决方案 2014-03-05      0个评论    来源:Safari ...

  5. 开发一个iOS应用没有那么容易

    导读:这是来自新加坡的 iOS 开发者 Kent Nguyen 发表在1月底的一篇博文.这篇吐槽文在 iOS 开发圈子里流传甚广,从原文150多个评论就可见一斑,现翻译如下. 让我们开门见山吧:做一个 ...

  6. IOS开发笔记 IOS如何访问通讯录

    IOS开发笔记  IOS如何访问通讯录 其实我是反对这类的需求,你说你读我的隐私,我肯定不愿意的. 幸好ios6.0 以后给了个权限控制.当打开app的时候你可以选择拒绝. 实现方法: [plain] ...

  7. web前端开发与iOS终端开发的异同[转]

    * {-webkit-tap-highlight-color: rgba(0,0,0,0);}html {-webkit-text-size-adjust: none;}body {font-fami ...

  8. 用HTML5/CSS3/JS开发Android/IOS应用框架大全

    现在人人都想成为安卓/IOS应用开发工程师.其实,安卓/IOS应用可以用很多种语言来实现.由于我们前端开发工程师,对HTML5/CSS/JavaScript的网络编程已经相当熟悉了.所以,今天大家将会 ...

  9. 玩转iOS开发:iOS中的GCD开发(三)

    上一章, 我们了解到了GCD里的一些队列和任务的知识, 也实践了一下, 同时我们也对主队列的一些小情况了解了一下, 比如上一章讲到的卡线程的问题, 如果没有看的朋友可以去看看玩转iOS开发:iOS中的 ...

  10. [Android开发学iOS系列] 工具篇: Xcode使用和快捷键

    [Android开发学iOS系列] 工具篇: Xcode使用和快捷键 工欲善其事必先利其器. 编辑 Cmd + N: 新建文件 Option + Cmd + N: 新建文件夹 Cmd + / : 注释 ...

随机推荐

  1. <你不知道的JavaScript>读书笔记

    近几天看了一本不错的 JavaScript 的书,是 Kyle Simpson 写的 <You Don't know JS>.这本书是 Kyle Simpson 在 Github 上的开源 ...

  2. 【JDK源码系列】ConcurrentHashMap

    并发永远是高性能的话题,而并发容器又是java中重要的并发工具,所以今天我们来分析一下Concurrent包中ConcurrentHashMap(以下简称Chashmap).普通容器在某些并发情况下的 ...

  3. 以 280W 数据为依据。对比SQL2008 表分区前和分区后的 T_SQL 效率

    一: 数据库的优化一直项目后期的重中之重,特别是当单表数据庞大到1000W时候.各种SQL语句执行效率都会慢很多.SQL 效率 与索引,行数据,列数据,以及Where 刷选字段类型 (效率 整数型大于 ...

  4. ACM——数的计算

    数的计算——(递归(超时)和非递归) 时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte总提交:1050            测试通过:31 ...

  5. ArryList vs LinkedList

    references: http://www.javaperformancetuning.com/articles/randomaccess.shtml http://stackoverflow.co ...

  6. string[] 和 arraylist互转及问题解决

    1,String 数组转成 list<String> String[] s={"1","2","3","5" ...

  7. selenium2.0处理case实例(二)

    本文通过具体代码处理过程, 来展示selenium中一些比较不常用的类的用法 1.javascriptExcutor,通过将driver强转成JavascriptExecutor类型, 调用execu ...

  8. cocos2d-x实战 C++卷 学习笔记--第6章 场景与层

    前言: 一个场景(Scene)是由多个层(Layer)组成,而且层的个数要至少是1,不能为0. 场景切换 场景切换相关函数 1)void  runWithScene(Scene*  scene) 该函 ...

  9. mysql学习笔记6——用phpmyadmin和在腾讯微云中创建数据库

    安装phpmyadmin就不多说了,对于新手,推荐使用wamp(windows系统),傻瓜式安装,很好用.安装完后在浏览器栏输入localhost

  10. OpenJudge/Poj 1251 丛林中的路/Jungle Roads

    1.链接地址: http://bailian.openjudge.cn/practice/1251/ http://poj.org/problem?id=1251 2.题目: 总时间限制: 1000m ...