翻译:iOS视图控制器编程指南(八)——Present视图控制器(Presenting a View Controller)

在屏幕上显示视图控制器有两种方法:嵌入到容器视图控制器中或者present这个视图控制器。容器视图控制器提供应用的主要导航,但present视图控制器同样也是一个重要的导航工具。可以在当前的视图控制器上直接present一个新的视图控制器。通常,当你希望实现modal界面时,可以present视图控制器,但你也可以使用它们用于其他用途。

UIViewController 类支持present视图控制器,可用于所有的视图控制器对象。你可以在任何其他视图控制器上present任何一个视图控制器,虽然UIKit可能重新路由该请求到不同的视图控制器上。present视图控制器会在原始视图控制器之间创建关系,原始视图控制器称为 presenting view controller,显示的新视图控制器称为presented view controller。这个关系是视图控制器层级结构的一部分,直到presented视图控制器被dismiss。

展示和过渡的过程

present一个视图控制器是一种快速而简单的方法在屏幕上推出新内容。UIKit内置present机制,允许使用内置或自定义动画来显示一个新的视图控制器。内置present和动画需要很少的代码因为UIKit处理了所有的工作。你也可以很容易的在任何视图控制器创建自定义present和动画。

你可以以编程方式或使用segue来发起视图控制器的present。如果在设计时你知道应用的导航,segue是发起present最简单的方式。更多动态界面,或者没有专门的控件发起segue的情况下,使用 UIViewController方法来present视图控制器。

Presentation Styles

presentation style 是一个视图控制器管理其屏幕上的外观。UIKit定义了许多标准的present风格,每个都有特定的外观和意图。你也可以定义自定义present风格。当设计你的应用时,为你的应用选择合适的present风格,并为要present的视图控制器的 modalPresentationStyle属性分配适合的常数。

Full-Screen Presentation Styles

Full screen presentation styles覆盖全部屏幕,防止与底层内容互动。在水平常规环境中,只有full-screen styles完全覆盖了底层内容。其余变暗或有透明度的视图允许部分底层视图控制器显示。在水平紧凑环境中,full-screen present方式自动采用UIModalPresentationFullScreen风格并覆盖所有底层内容。

图8-1 说明在水平常规环境使用UIModalPresentationFullScreen,UIModalPresentationPageSheetUIModalPresentationFormSheet风格present方式的外观。在图中,在左上角的绿色视图控制器present在右上角的蓝色视图控制器,各种present风格如下。对于一些present风格,UIKit在两个视图控制器内容之间插入一个半透明视图。

图8-1 全屏present风格

注意

当使用UIModalPresentationFullScreen风格present一个视图控制器时,UIKit通常在完成过渡动画后删除底层视图控制器的视图。你可以通过指定UIModalPresentationOverFullScreen风格防止删除这些视图。当present的视图控制器有透明区域让底层内容显示时可以采用这种风格。

当使用一种present 风格时,视图控制器启动的present必须覆盖整个屏幕。如果将要present的视图控制器不能覆盖整个屏幕,UIKit遍历视图控制器层级直到找到一个覆盖整个屏幕的视图控制器。如果不能找到一个中间视图控制器充满屏幕,UIKit使用窗口的根视图控制器。

The Popover Style

UIModalPresentationPopover风格以弹出窗口的方式显示在视图控制器上。popover用于显示额外信息或项目列表中选中的对象。在横向常规环境中,popover视图仅覆盖屏幕的一部分,如图8-2所示。在横向紧凑环境中,popover默认采用UIModalPresentationOverFullScreen present方式。在popover视图外点击, popover视图将自动dismiss。

图8-2 弹窗present风格

因为在水平紧凑环境中,popover采用full-screen 的present方式,通常需要修改popover代码处理适配。在full-screen模式,需要一种方法dismiss掉present的popover。你可以通过添加一个按钮,将popover嵌入到将要dismiss的容器视图控制器,或者改变自适应行为本身。

如何配置弹窗,参见在视图控制器上present弹窗( Presenting a View Controller in a Popover)。

The Current Context Styles

UIModalPresentationCurrentContext 风格在界面覆盖了一个特殊的视图控制器。当使用contextual风格,通过设置 definesPresentationContext属性为YES,指定要覆盖的视图控制器。图8-3说明了current context 只覆盖分屏视图控制器的一个子视图控制器。

图8-3 当前环境present风格

注意

当使用UIModalPresentationFullScreen风格present一个视图控制器,UIKit通常在过渡动画完成后删除底层视图控制器的视图。可以设置UIModalPresentationOverCurrentContext风格,防止删除那些视图。当present的视图控制器有透明区域让底层内容显示时,可以使用该风格。

定义视图控制器还可以在present过程中定义过渡动画。通常,当使用present视图控制器的 modalTransitionStyle属性,UIKit渲染视图控制器到屏幕。如果present context视图控制器的 providesPresentationContextTransitionStyle值设为YES,UIKit使用视图控制器的modalTransitionStyle属性代替。

当过渡到水平紧凑的环境,current context风格采用 UIModalPresentationFullScreen 风格。为了改变该行为,使用自适应present委托指定不同的present风格或视图控制器。

Custom Presentation Styles

UIModalPresentationCustom风格使用自定义的风格present视图控制器。创建一个自定义风格包括子类化UIPresentationController ,使用其方法来渲染任何自定义视图到屏幕上并设置present视图控制器的大小和位置。present控制器还处理由于视图控制器的trait变化引起的适配。

如何定义自定义present视图控制器的信息,参见创建自定义present( Creating Custom Presentations)。

Transition Styles

Transition风格决定用于显示present视图控制器的动画类型。对于内置transition风格,你可以为present视图控制器的 modalTransitionStyle属性指定一种标准transition风格。当present视图控制器,UIKit创建相应的动画风格。例如,图8-4说明了标准slide-up过渡(UIModalTransitionStyleCoverVertical)如何视图控制器渲染到屏幕上。视图控制器B开始在屏幕外,并覆盖到视图控制器A上。当dismiss视图控制器B,动画逆转,B下滑露出A。

图8-4 视图控制器的过渡动画

可以使用动画对象和过渡代理来创建自定义过渡。动画对象为屏幕上放置的视图控制器创建过渡动画。过渡代理在合适的时间为UIKit提供动画对象。更多关于如何实现自定义过渡的信息,参见自定义过渡动画(Customizing the Transition Animations)。

present和显示一个视图控制器

UIViewController类提供两种方法来显示一个视图控制器:

  • showViewController:sender:showDetailViewController:sender:方法为显示视图控制器提供最大限度的适应性和灵活性。这些方法让present视图控制器决定如何最好的处理present。例如,容器视图控制器可能合并视图控制器作为子视图控制器而不是以模态的方式present。默认以模态的方式present视图控制器。
  • presentViewController:animated:completion: 方法总是以模态的方式显示视图控制器。视图控制器调用这个方法可能不会最终处理present但总是以模态的方式present。在水平紧凑环境中,该方法采用该present风格。

showViewController:sender:showDetailViewController:sender: 方法是启动present的首选方法。视图控制器可以调用它们,而不用知道任何关于视图控制器层级结构或当前视图控制器在层级结构的位置。这些方法使重用视图控制器更加容易,而无需编写条件代码路径。

present视图控制器

有几种方法可以present视图控制器:

关于如何dismiss使用这些技术present的视图控制的更多信息,参见dismiss一个presented的视图控制器( Dismissing a Presented View Controller)。

显示视图控制器

当使用和方法,得到屏幕上一个新的视图控制器的过程很简单:

  1. 创建你希望present的视图控制器对象。当创建视图控制器时,你负责初始化它执行任何所需的任何数据。
  2. 设置新视图控制器的 modalPresentationStyle属性是首选present风格。该风格可能不用于最终的present。
  3. 设置视图控制器的modalTransitionStyle属性设置所需的过渡动画风格。该风格可能不用于最终的present。
  4. 调用当前视图控制器的 showViewController:sender:showDetailViewController:sender:方法。

UIKit转发showViewController:sender:showDetailViewController:sender: 方法的调用给present视图控制器。视图控制器可以决定如何最好的执行present,并且可以根据需呀改变present和过渡风格。例如,导航控制器可能push该视图控制器到导航堆栈。

关于显示视图控制器和以模态的方式present视图控制器的差异信息,参见present和显示视图控制器( Presenting Versus Showing a View Controller)。

以模态的方式present视图控制器

当直接present视图控制器,你需要告诉UIKit你希望视图控制器如何显示以及如何渲染到屏幕上。

创建你希望present的视图控制器对象。当创建视图控制器时,你负责初始化它执行任何所需的任何数据。

  1. 设置新视图控制器的 modalPresentationStyle 属性为所需的present风格。
  2. 设置视图控制器的 modalTransitionStyle属性为所需的动画风格。
  3. 调用当前视图控制器的 presentViewController:animated:completion:方法。

调用presentViewController:animated:completion: 方法的视图控制器可能不是最终执行模态present的视图控制器。present风格决定了视图控制器如何被present,包括present视图控制器所需的特征。例如,一个全屏present必须由一个全屏视图控制器启动。如果当前present视图控制器不合适,UIKit遍历视图控制器层级直到找到合适的。完成模态present后,UIKit更新受影响的视图控制器的presentingViewControllerpresentedViewController属性。

列表8-1 演示了如何以编程的方式present一个视图控制器。当用户添加一个新视图控制器,应用提示用户输入present导航视图控制器的基本信息。被选中的导航控制器会在标准的地方放置一个取消和完成按钮。使用导航控制器使扩展新界面更加容易。你所需要做的是push新视图控制器到导航堆栈。

列表8-1 以编程的方式present一个视图控制器

<pre><code>

    • (void)add:(id)sender {
  1. // Create the root view controller for the navigation controller
  2. // The new view controller configures a Cancel and Done button for the
  3. // navigation bar.
  4. RecipeAddViewController *addController = [[RecipeAddViewController alloc] init];
  5. addController.modalPresentationStyle = UIModalPresentationFullScreen;
  6. addController.transitionStyle = UIModalTransitionStyleCoverVertical;
  7. [self presentViewController:addController animated:YES completion: nil];
  8. }
    </pre></code>

以弹窗形式present视图控制器

在present视图控制器之前,popover需要额外的配置。在设置模态present风格为 UIModalPresentationPopover后,配置一下popover相关属性:

可以使用 UIPopoverPresentationController对象在需要时调整弹窗的外观。弹窗present控制器还支持代理对象,可以使用它来响应在present过程中的变化。例如,你可以使用代理来响应弹窗在屏幕上出现、消失或重新定位。关于该对象的更多信息,参见UIPopoverPresentationController类引用(UIPopoverPresentationController Class Reference)。

dismiss一个presented的视图控制器

调用presenting视图控制器的dismissViewControllerAnimated:completion:方法来dismiss一个presented的视图控制器。你可以在presented视图控制器本身的方法。当presented视图控制器调用该方法,UIKit自动转发请求到presenting视图控制器。

在dismiss视图控制器前保存任何重要信息。dismiss视图控制器会将其从视图控制器层级结构删除并从屏幕上删除视图。如果在其他地方存储的视图控制器没有强引用,dismiss该视图控制器会释放与之关联的内存。

如果presented视图控制器必须返回数据到presenting视图控制器,使用 delegation 设计模式来完成传递。代理使应用视图控制器的重用更容易。使用代理,presented视图控制器存储代理对象的引用,实现正式protocol的方法。Presented视图控制器在代理调用这些方法用于收集结果。在典型的实现中,presenting视图控制器作为presented视图控制器的代理。

present在不同storyboard种定义的视图控制器

虽然在同一storyboard中的两个视图控制器之间可以创建segue,但在不同storyboard中不能创建segue。当你希望显示存储在另一个storyboard中的视图控制器时,你必须在present之前显式的实例化该视图控制器,如列表8-2所示。例子以模态的方式present视图控制器,但你可以push它到导航控制器或以其他方式显示。

列表8-2 加载storyboard中的视图控制器

<pre><code>

  1. UIStoryboard* sb = [UIStoryboard storyboardWithName:@"SecondStoryboard" bundle:nil];
  2. MyViewController* myVC = [sb instantiateViewControllerWithIdentifier:@"MyViewController"];
  3. // Configure the view controller.
  4. // Display the view controller
  5. [self presentViewController:myVC animated:YES completion:nil];
    </pre></code>

没有要求你必须在应用中创建多个storyboard。不过,在这里有一些情况下多个storyboard可能有用:

  • 你有一个大的编程团队,不同的用户界面分配给团队的不同部分。每个团队拥有不同的storyboard文件以减少冲突。
  • 你购买或创建一个库预定义了视图控制器类型集合;这些视图控制器的内容定义在库中的storyboard中。
  • 你有需要在屏幕外显示的内容。在这种情况下,你可能保持所有视图控制器与单独storyboard的视图控制器相关。相同场景的另一种模式是编写一个自定义segue。

官方原文地址:

https://developer.apple.com/library/prerelease/ios/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容