iOS review系列之Presenting a View Controller

iOS review系列之使用Segues
iOS review系列之自定义转场动画
iOS review系列之UIViewController
iOS review系列之Creating Custom Presentations

Presenting a ViewController

有两种方法可以在屏幕上显示视图控制器:将其嵌入到容器视图控制器中或显示(present )出来。容器视图控制器提供了应用程序的主要导航,但是展示视图控制器(presenting view controllers)也是重要的导航工具。您可以直接使用present在当前控件之上显示一个新的视图控制器。通常,在您想要实现模态界面时会present视图控制器,但也可以将它们用于其他目的。

UIViewController该类内置了对展示视图控制器(presenting view controllers)的支持,并且对所有视图控制器对象都可用。您可以从任何其他视图控制器中present任何视图控制器,尽管UIKit可能会将请求重新路由到其他视图控制器。展示视图控制器会在原始视图控制器(称为要展示视图控制器presenting view controller)和要显示的新视图控制器(称为已展示视图控制器presented view controller)之间建立关系。此关系形成视图控制器层次结构的一部分,并保持不变,直到关闭已显示的视图控制器为止。

展示和转场过程 - The Presentation and Transition Process

展示视图控制器是一种将新内容动画化到屏幕上的快速简便的方法。UIKit内置的展示presentation机制使您可以使用内置或自定义动画显示新的视图控制器。内置的展示presentation和动画几乎不需要代码,因为UIKit可以处理所有工作。这样您可以轻松创建自定义的展示presentation和动画,并将其与任何视图控制器一起使用。

您可以以编程方式或使用segues的方式启动视图控制器的展示。如果您在设计时就知道应用程序的导航,则segues是启动展示presentation的最简单方法。对于更具动态性的界面,或者在没有专用控件启动segue的情况下,请使用UIViewController的方法来展示视图控制器。

展示风格 - Presentation Styles

视图控制器 的展示风格控制着它在屏幕上的外观。UIKit定义了许多标准的展示风格,每种展示风格都有特定的外观和意图。您还可以定义自己的自定义展示风格。在设计应用程序时,请选择最适合您要尝试的展示方式,并将适当的常量分配给modalPresentationStyle要展示的视图控制器的属性。

全屏展示风格

全屏展示风格涵盖了整个屏幕,从而避免了与基础内容的交互。在水平规则的环境中,只有一种全屏样式会完全覆盖基础内容。其余部分合并了变暗视图或透明度,以允许基础视图控制器的某些部分通过显示。在水平紧凑的环境中,全屏展示presentation会自动适应UIModalPresentationFullScreen样式并覆盖所有基础内容。

下图使用的介绍的外观UIModalPresentationFullScreenUIModalPresentationPageSheetUIModalPresentationFormSheet样式在水平规则环境。在图中,左上角的绿色视图控制器展示出在右上角的蓝色视图控制器,每种显示样式的结果如下所示。对于某些表示样式,UIKit在两个视图控制器的内容之间插入一个调暗视图。

](https://upload-images.jianshu.io/upload_images/2270079-72464e8c94ed5b31.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

当使用UIModalPresentationFullScreen样式显示视图控制器时,UIKit通常会在转场动画结束后删除基础视图控制器的视图。您可以通过指定UIModalPresentationOverFullScreen样式来防止删除这些视图。当显示的视图控制器具有透明区域以使基础内容显示出来时,您可以使用该样式。

使用全屏演示样式之一时,启动演示的视图控制器本身必须覆盖整个屏幕。如果展示的视图控制器未覆盖整个屏幕,则UIKit会向上移动视图控制器层次结构,直到找到一个可以的视图控制器层次结构。如果找不到用于填充屏幕的中间视图控制器,则UIKit将使用window的根视图控制器。

弹出风格-The Popover Style

UIModalPresentationPopover样式显示在一个弹出框中的视图控制器。弹出框对于显示其他信息或与聚焦或选定对象有关的项目列表很有用。在水平固定的环境中,弹出框仅覆盖部分屏幕,如下图所示。在水平紧凑的环境中,UIModalPresentationOverFullScreen默认情况下,弹出框会适应展示样式。在弹出框的外部点击可自动关闭弹出框。

Popover展示样式

由于弹出框可在水平紧凑的环境中适应全屏演示,因此通常需要修改弹出框代码以处理该适应。在全屏模式下,您需要一种方法来消除显示的弹出框。您可以通过添加按钮,将弹出框嵌入到可允许的容器视图控制器中或更改自适应行为本身来做到这一点。

有关如何配置弹出框演示的提示,请参阅在弹出窗口中展示视图控制器

当前的上下文样式-The Current Context Styles

UIModalPresentationCurrentContext样式涵盖了界面中的特定视图控制器。使用上下文样式时,可以通过为指定要覆盖的视图控制器的definesPresentationContext属性设置为YES。下图说明了当前上下文表示,该上下文表示仅涵盖拆分视图控制器的一个子视图控制器。

图8-3 当前上下文表示样式

当使用UIModalPresentationFullScreen样式显示视图控制器时,UIKit通常会在转场动画结束后删除基础视图控制器的视图。您可以通过指定UIModalPresentationOverCurrentContext样式来防止删除这些视图。当显示的视图控制器具有透明区域以使基础内容显示出来时,您可以使用该样式。

定义展示上下文的视图控制器还可以定义在演示过程中使用的转场动画。通常,UIKit使用modalTransitionStyle提供的视图控制器属性中的值在屏幕上对视图控制器进行动画处理。如果展示presentation上下文视图控制器将其providesPresentationContextTransitionStyle设置为YES,则UIKit会改用该视图控制器modalTransitionStyle属性中的值。

转场到水平紧凑的环境时,当前的上下文样式将适应该UIModalPresentationFullScreen样式。若要更改该行为,请使用自适应展示委托(adaptive presentation delegate)来指定其他展示样式或视图控制器。

自定义展示样式

UIModalPresentationCustom样式使您可以使用定义的自定义样式来展示视图控制器。创建自定义样式涉及子类化UIPresentationController并使用其方法在屏幕上创建任何自定义视图的动画,并设置显示的视图控制器的大小和位置。展示控制器还可以处理由于对展示的视图控制器的特征进行更改而发生的任何调整。

有关如何定义自定义展示presentation控制器的信息,请参见创建自定义展示presentation

转场样式

转场样式确定用于显示展示的视图控制器的动画的类型。对于内置转场样式,可以将一种标准转场样式分配给modalTransitionStyle要展示的视图控制器的属性。当您展示视图控制器时,UIKit会创建与该样式相对应的动画。例如,下图说明了标准的滑动向上转场(UIModalTransitionStyleCoverVertical)如何在屏幕上展示视图控制器的动画。视图控制器B开始在屏幕外启动,并动画运行到视图控制器A的顶部上方结束。关闭视图控制器B时,动画将反转,因此B向下滑动以显示A。

图8-4 视图控制器的转场动画

您可以使用动画器对象和转场委托创建自定义转场。动画对象创建用于将视图控制器放置在屏幕上的转场动画。转场委托在适当的时候将该动画对象提供给UIKit。有关如何实现自定义转场的信息,请参见“ 自定义转场动画”

展示与显示视图控制器-Presenting Versus Showing a View Controller

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

  • showViewController:sender:showDetailViewController:sender:方法提供显示视图控制器最自适应和灵活的方式。这些方法使展示视图控制器可以决定如何最好地处理展示。例如,容器视图控制器可以将视图控制器作为子级合并,而不是模态地展示。默认行为以模态形式显示视图控制器。
  • presentViewController:animated:completion:方法始终以模态方式显示视图控制器。调用此方法的视图控制器可能最终不会处理展示presentation,但是展示presentation始终是模态的。此方法适合样式适合水平紧凑的环境。

showViewController:sender:showDetailViewController:sender:方法是启动展示的首选方式。视图控制器可以调用它们而无需了解其余视图控制器层次结构或当前视图控制器在该层次结构中的位置。这些方法还使您更容易在应用的不同部分中重用视图控制器,而无需编写条件代码路径。

展示视图控制器-Presenting a View Controller

有几种方法可以启动视图控制器的展示:

  • 使用segue自动展示视图控制器。segue使用您在Interface Builder中指定的信息实例化并展示视图控制器。有关如何配置segues的更多信息,请参阅《使用Segues》
  • 使用showViewController:sender:showDetailViewController:sender:方法展示视图控制器。在自定义视图控制器中,您可以将这些方法的行为更改为更适合您的视图控制器的行为。
  • 调用该presentViewController:animated:completion:方法以模态的方式类展示视图控制器。

有关如何关闭使用这些技术之一展示的视图控制器的信息,请参见消除展示的视图控制器

显示视图控制器 - Showing View Controllers

使用showViewController:sender:showDetailViewController:sender:方法时,在屏幕上显示新视图控制器的过程很简单:

  1. 创建你想要展示的视图控制器对象。创建视图控制器时,您有责任使用执行任务所需的任何数据对其进行初始化。
  2. 设置新的视图控制器的modalPresentationStyle属性为首选的展示样式。在最终的展示presentation中可能不会使用此样式。
  3. 设置新的视图控制器的modalTransitionStyle属性为所需的转场动画样式。此样式可能不会在最终动画中使用。
  4. 调用当前视图控制器的showViewController:sender:showDetailViewController:sender:方法。

UIKit将对showViewController:sender:showDetailViewController:sender:方法的调用转发给相应的展示视图控制器。然后,该视图控制器可以决定如何最好地执行展示,并可以根据需要更改展示和转场样式。例如,导航控制器可能会将视图控制器推入其导航堆栈中。

有关显示视图控制器和以模态方式显示它们之间差异的信息,请参阅展示与显示视图控制器

模态展示视图控制器-Presenting View Controllers Modally

直接显示视图控制器时,您告诉UIKit您希望新的视图控制器如何显示以及如何在屏幕上对其进行动画处理。

  1. 创建要展示的视图控制器对象。

    创建视图控制器时,您有责任使用执行任务所需的任何数据对其进行初始化。

  2. 设置新的视图控制器的modalPresentationStyle属性所需的演示样式。

  3. 设置视图控制器的modalTransitionStyle属性为所需的动画样式。

  4. 调用当前视图控制器的presentViewController:animated:completion:方法。

调用该presentViewController:animated:completion:方法的视图控制器可能不是实际执行模式展示的视图控制器。展示样式确定如何展示视图控制器,包括展示视图控制器所需的特性。例如,全屏演示必须由全屏视图控制器启动。如果当前显示的视图控制器不合适,则UIKit遍历视图控制器层次结构,直到找到合适的层次结构为止。模态展示完成后,UIKit将更新受影响的视图控制器的presentingViewControllerpresentedViewController属性。

下面代码演示了如何以编程方式展示视图控制器。当用户添加新食谱时,该应用会通过显示导航控制器来提示用户有关食谱的基本信息。选择了导航控制器,以便可以在标准位置放置“取消并完成”按钮。使用导航控制器还使将来扩展新配方界面变得更加容易。您要做的就是将新的视图控制器推入导航堆栈中。

- (void)add:(id)sender {
   // Create the root view controller for the navigation controller
   // The new view controller configures a Cancel and Done button for the
   // navigation bar.
   RecipeAddViewController *addController = [[RecipeAddViewController alloc] init];
 
   addController.modalPresentationStyle = UIModalPresentationFullScreen;
   addController.transitionStyle = UIModalTransitionStyleCoverVertical;
   [self presentViewController:addController animated:YES completion: nil];
}

在弹出框中显示视图控制器

弹出框需要额外的配置才能展示。将模态展示样式设置为UIModalPresentationPopover,配置以下与Popover相关的属性:

  • 设置您的视图控制器的preferredContentSize属性设置为所需的大小。
  • 使用关联的UIPopoverPresentationController对象设置弹出锚点,可以从视图控制器的popoverPresentationController属性访问该对象。仅设置以下一项:
    • 设置barButtonItem属性为条形按钮项(bar button)。
    • 设置sourceViewsourceRect属性为众多视图中某个视图的特定区域。

您可以根据需要使用该UIPopoverPresentationController对象对弹出窗口的外观进行其他调整。popover展示控制器还支持一个委托对象,您可以使用该委托对象在演示过程中响应更改。例如,您可以使用委托在弹出窗口出现,消失或在屏幕上重新放置时做出响应。有关此对象的更多信息,请参见UIPopoverPresentationController类参考

消除展示的视图控制器

要关闭展示的视图控制器,请调用要展示的视图控制器的dismissViewControllerAnimated:completion:方法。您也可以在已显示的视图控制器本身上调用此方法。当您在显示的视图控制器上调用方法时,UIKit会自动将请求转发到显示的视图控制器。

在关闭任何重要信息之前,请务必先将其保存。关闭视图控制器会将其从视图控制器层次结构中删除,并将其视图从屏幕中删除。如果您没有在其他位置上强引用此视图控制器,则将其关闭会释放与其关联的内存。

如果提供的视图控制器必须将数据返回给提供的视图控制器,请使用委托设计模式来促进传输。通过委托,可以更轻松地在应用程序的不同部分重用视图控制器。通过委托,所展示的视图控制器存储着对对委托对象的引用,该对象实现了正式的协议中的方法。在收集结果时,展示的视图控制器在其委托上调用这些方法。在典型的实现中,要展示的视图控制器使其本身成为其已展示视图控制器的委托。

展示在其他情节提要中定义的视图控制器

尽管可以在同一故事中的视图控制器之间创建segues,但不能在不同故事板之间创建segues。如果要显示存储在其他故事板中的视图控制器,则必须在显示它之前显式地实例化该视图控制器,如下面代码所示。该示例以模态的形式展示了视图控制器,但是您可以将其推到导航控制器上或以其他方式显示它。

UIStoryboard* sb = [UIStoryboard storyboardWithName:@"SecondStoryboard" bundle:nil];
MyViewController* myVC = [sb instantiateViewControllerWithIdentifier:@"MyViewController"];
 
// Configure the view controller.
 
// Display the view controller
[self presentViewController:myVC animated:YES completion:nil];

无需在应用程序中创建多个故事板。不过,在某些情况下,使用多个故事板可能会有用:

  • 您有一个庞大的编程团队,并且用户界面的不同部分分配给团队的不同人员。每个团队在不同的故事板文件中拥有部分用户界面,以最大程度地减少竞争。
  • 您购买或创建了一个库,该库预定义了视图控制器类型的集合。这些视图控制器的内容在库提供的故事板中定义。
  • 您具有需要在外部屏幕上显示的内容。在这种情况下,您可以将与备用屏幕关联的所有视图控制器放在单独的故事板中。另一种模式是在相同场景下写自定义segue。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,158评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,600评论 1 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,785评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,655评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,075评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,002评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,146评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,918评论 0 211
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,671评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,838评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,318评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,636评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,343评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,187评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,982评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,126评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,934评论 2 279