有两种方法在屏幕上显示视图控制器:将其嵌入到容器视图控制器中或呈现它。 容器视图控制器提供应用程序的主导航,但是呈现视图控制器也是一个重要的导航工具。 您使用直接演示在当前视图控制器的顶部显示新的视图控制器。 通常,当您想要实现模态界面时,您可以使用呈现视图控制器,但是您也可以将它们用于其他用途。
支持呈现视图控制器内置在UIViewController类中,并且可用于所有视图控制器对象。 您可以呈现来自任何其他视图控制器的任何视图控制器,虽然UIKit可能会将请求重新路由到不同的视图控制器。 呈现视图控制器创建被称为呈现视图控制器的原始视图控制器和被显示的新视图控制器之间的关系,被称为呈现的视图控制器。 此关系形成视图控制器层次结构的一部分,并且保持就位,直到呈现的视图控制器被解除。
展示与过渡过程
呈现视图控制器是一种快速和简单的方式来将新内容设置到屏幕上。 UIKit中内置的演示机制允许您使用内置或自定义动画显示新的视图控制器。 内置的展示和动画需要很少的代码,因为UIKit处理所有的工作。 您也可以创建自定义展示和动画,而不需要额外的工作,并与任何视图控制器使用它们。
您可以以编程方式或使用segues启动视图控制器的呈现。 如果你在设计时知道你的应用程序的导航,segues是最简单的方式来启动界面。 对于更多动态界面,或在没有专门控制来启动segue的情况下,使用UIViewController的方法来呈现视图控制器。
呈现方式
视图控制器的呈现方式控制其在屏幕上的外观。 UIKit定义了许多标准的呈现方式,每个都有一个特定的外观和意图。 您还可以定义自己的自定义呈现方式。 在设计应用程序时,选择最适合您想要做的操作的呈现方式,并将适当的时候分配给要呈现的视图控制器的modalPresentationStyle属性。
全屏呈现方式
全屏呈现方式覆盖整个屏幕,防止与底层内容的交互。 在水平常规环境中,只有一个全屏方式完全覆盖基础内容。 其余包含调光视图或透明度,以允许下层视图控制器的部分显示。 在水平紧凑的环境中,全屏演示自动适应UIModalPresentationFullScreen方式并涵盖所有底层内容。
图8-1说明使用uimodalpresentationfullscreen,uimodalpresentationpagesheet呈现方式的外观,并在水平正常的环境uimodalpresentationformsheet风格。在图中,顶部左侧的绿色视图控制器呈现顶部右侧的蓝色视图控制器,每个显示样式的结果如下所示。对于一些呈现方式,UIKit插入一个调光的视图的两个视图控制器的内容。
图8-1全屏呈现方式
注意
当使用UIModalPresentationFullScreen方式呈现视图控制器时,UIKit通常在
转换动画完成后删除基础视图控制器的视图。 您可以通过指定
UIModalPresentationOverFullScreen样式来防止删除这些视图。 当呈现的视
图控制器具有允许基础内容显示的透明区域时,您可以使用该样式。
当使用全屏呈现方式之一时,发起呈现的视图控制器必须自己覆盖整个屏幕。 如果呈现视图控制器不覆盖屏幕,UIKit会在视图控制器层次结构上查找覆盖全屏的,直到它找到一个。 如果它找不到填充屏幕的中间视图控制器,UIKit使用窗口的根视图控制器。
弹出方式
UIModalPresentationPopover方式在弹出视图中显示视图控制器。 弹出式窗口可用于显示附加信息或与关注或选定对象相关的项目列表。 在水平常规环境中,弹出视图仅覆盖屏幕的一部分,如图8-2所示。 在水平紧凑的环境中,默认情况下,popovers适应UIModalPresentationOverFullScreen表示方式。 在popover视图之外轻击会自动关闭popover。
图8-2 弹出呈现方式
因为弹出方式适合在水平紧凑的环境中的全屏显示,所以通常需要修改弹出方式代码来处理适配。 在全屏模式下,您需要一种方法来关闭所显示的popover。 你可以通过添加一个按钮,将popover嵌入一个可忽略的容器视图控制器,或者改变自适应行为本身。
当前上下文方式
UIModalPresentationCurrentContext样式涵盖了接口中的特定视图控制器。 当使用上下文方式时,通过将其definitionsPresentationContext属性设置为YES来指定要覆盖哪个视图控制器。 图8-3示出了仅覆盖拆分视图控制器的一个子视图控制器的当前上下文表示。
图8-3 当前上下文呈现方式
注意
当使用UIModalPresentationFullScreen方式呈现视图控制器时,UIKit通常在
转换动画完成后删除基础视图控制器的视图。 您可以通过指定
UIModalPresentationOverCurrentContext样式来防止删除这些视图。 当呈现
的视图控制器具有允许基础内容显示的透明区域时,您可以使用该方式。
定义呈现上下文的视图控制器还可以定义在呈现期间使用的转换动画。 通常,UIKit使用呈现的视图控制器的modalTransitionStyle属性中的值在屏幕上动画显示控制器。 如果演示文稿上下文视图控制器的providesPresentationContextTransitionStyle设置为YES,UIKit将使用该视图控制器的modalTransitionStyle属性中的值。
当转换到水平紧凑环境时,当前上下文样式适应UIModalPresentationFullScreen样式。 要更改此行为,请使用自适应呈现委派来指定不同的呈现样式或视图控制器。
自定义呈现方式
UIModalPresentationCustom方式允许你使用定义的自定义方式来呈现视图控制器。 创建自定义方式涉及对UIPresentationController子类化,并使用其方法将任何自定义视图动画化到屏幕上,并设置呈现的视图控制器的大小和位置。 呈现控制器还处理由于呈现的视图控制器的特性的改变而发生的任何适配。
过渡方式
过渡方式确定用于显示所呈现的视图控制器的动画类型。 对于内置的转换方式,可以将一个标准转换方式分配给要显示的视图控制器的modalTransitionStyle属性。 当您呈现视图控制器时,UIKit将创建与该样式对应的动画。 例如,图8-4说明了标准上滑过渡(UIModalTransitionStyleCoverVertical)如何在屏幕上动画视图控制器。 视图控制器B从屏幕开始并且向上和向上移动视图控制器A的顶部。当视图控制器B被关闭时,动画反转,使得B向下滑动以显示A.
图8-4视图控制器的过渡动画
您可以使用animator对象和转换委托创建自定义转场。 动画制作器对象创建用于将视图控制器放置在屏幕上的过渡动画。 转换委托在适当的时间将动画对象提供给UIKit。
呈现或显示视图控制器
UIViewController类提供了两种显示视图控制器的方法:
- showViewController:sender:和showDetailViewController:sender:方法提供了最适应和灵活的方式来显示视图控制器。 这些方法让呈现视图控制器决定如何最好地处理呈现。 例如,容器视图控制器可以将视图控制器合并为子控制器,而不是模态地呈现它。 默认行为以模态方式呈现视图控制器。
- presentViewController:animated:completion:方法总是以模态方式显示视图控制器。 调用此方法的视图控制器可能不会最终处理呈现,但呈现总是模态。 此方法适应水平紧凑环境的呈现风格。
showViewController:sender:和showDetailViewController:sender:方法是启动呈现视图的首选方法。 视图控制器可以在不知道关于视图控制器层次结构的其余部分或当前视图控制器在该层次结构中的位置的任何情况下调用它们。 这些方法还使得更容易在应用程序的不同部分重用视图控制器,而无需编写条件代码路径。
呈现视图控制器
有几种方式来启动视图控制器的呈现:
- 使用segue自动呈现视图控制器。 segue使用您在Interface Builder中指定的信息实例化并呈现视图控制器。
- 使用showViewController:sender:或showDetailViewController:sender:方法来显示视图控制器。 在自定义视图控制器中,您可以将这些方法的行为更改为更适合于视图控制器的行为。
- 调用presentViewController:animated:completion:方法以模态方式呈现视图控制器。
显示视图控制器
当使用showViewController:sender:和showDetailViewController:sender:方法时,在屏幕上获取新的视图控制器的过程是直接的:
- 创建要显示的视图控制器对象。 在创建视图控制器时,您有责任使用执行其任务所需的任何数据对其进行初始化。
- 将新视图控制器的modalPresentationStyle属性设置为首选显示方式。 此方式可能不会在最终呈现中使用。
- 将视图控制器的modalTransitionStyle属性设置为所需的过渡动画方式。 此方式可能不会在最终的动画中使用。
- 调用当前视图控制器的showViewController:sender:和showDetailViewController:sender:方法。
UIKit将对showViewController:sender:和showDetailViewController:sender:方法的调用转发到相应的呈现视图控制器。 然后,视图控制器可以决定如何最好地执行呈现,并且可以根据需要改变呈现和转换样式。 例如,导航控制器可以将视图控制器推到其导航堆栈上。
模式地呈现视图控制器
当直接呈现视图控制器时,您可以告诉UIKit如何显示新的视图控制器以及如何在屏幕上动画。
- 创建要显示的视图控制器对象。
在创建视图控制器时,您有责任使用执行其任务所需的任何数据对其进行初始化。 - 将新视图控制器的modalPresentationStyle属性设置为所需的显示样式。
- 将视图控制器的modalTransitionStyle属性设置为所需的动画样式。
- 调用当前视图控制器的presentViewController:animated:completion:方法。
调用presentViewController:animated:completion:方法的视图控制器可能不是实际执行模态呈现的视图控制器。 呈现风格确定如何呈现视图控制器,包括呈现视图控制器所需的特性。 例如,全屏显示必须由全屏视图控制器启动。 如果当前呈现视图控制器不合适,UIKit会遍历视图控制器层次结构,直到它找到一个。 完成模态显示后,UIKit将更新受影响的视图控制器的presentingViewController和presentedViewController属性。
清单8-1演示了如何以编程方式呈现视图控制器。 当用户添加新配方时,应用程序通过呈现导航控制器来提示用户关于配方的基本信息。 选择了一个导航控制器,以便有一个标准的地方放置取消和完成按钮。 使用导航控制器还使得将来更容易扩展新的配方界面。 所有你需要做的是在导航堆栈上推新的视图控制器。
清单8-1以编程方式呈现视图控制器
- (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后,请配置以下与弹出相关的属性:
- 将视图控制器的preferredContentSize属性设置为所需的大小。
- 使用关联的UIPopoverPresentationController对象设置弹出锚点,该对象可以从视图控制器的popoverPresentationController属性访问。 仅设置以下选项之一:
* 将barButtonItem属性设置为bar按钮项。
* 将sourceView和sourceRect属性设置为其中一个视图中的特定区域。
您可以使用UIPopoverPresentationController对象根据需要对弹出的外观进行其他调整。 弹出呈现控制器还支持一个委托对象,您可以使用它来响应演示过程中的更改。 例如,您可以使用代理在弹出窗口出现,消失或在屏幕上重新定位时进行响应。
取消呈现的视图控制器
要关闭提交的视图控制器,请调用呈现视图控制器的dismissViewControllerAnimated:completion:方法。 您还可以在呈现的视图控制器本身上调用此方法。 当您在提供的视图控制器上调用该方法时,UIKit自动将请求转发到呈现视图控制器。
在关闭视图控制器之前,始终从视图控制器保存任何重要信息。 取消视图控制器会从视图控制器层次结构中删除它,并从屏幕中删除它的视图。 如果您没有强烈引用存储在其他位置的视图控制器,则关闭它会释放与其关联的内存。
如果呈现的视图控制器必须将数据返回给呈现视图控制器,则使用委托设计模式来促进传送。 委托使得在应用程序的不同部分中重用视图控制器更加容易。 使用委托,所呈现的视图控制器存储对实现来自形式协议的方法的委托对象的引用。 当它收集结果时,呈现的视图控制器在其委托上调用这些方法。 在典型的实现中,呈现视图控制器使其自身成为其呈现的视图控制器的委托。
虽然可以在同一故事板中的视图控制器之间创建段,但是不能在故事板之间创建段。 当要显示存储在不同故事板中的视图控制器时,必须在显示之前显式地实例化该视图控制器,如清单8-2所示。 该示例以模态呈现视图控制器,但您可以将其推送到导航控制器或以其他方式显示它。
清单8-2从故事板加载视图控制器
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。