ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC=5] * * * * * >原文链接 :[Presenting a View Controller](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW1) 在屏幕上显示视图控制器有两种方法:将其嵌入到容器视图控制器中或直接显示它。容器视图控制器提供了一个应用程序的主要导航,但弹出视图控制器也是一个重要的导航工具。您可以使用直接显示的方式来在当前的视图之上显示一个新的视图控制器。 通常,当您想要显示弹出页面时,你可以直接显示的方式展示视图控制器,但是您也可以将它们用于其他目的。 UIViewController 内置支持直接弹出视图控制器,并可用于所有视图控制器对象。 可以从任何一个视图控制器直接弹出另一个视图控制器,尽管 UIKit 可能会将请求重新路由到不同的视图控制器。 直接弹出视图控制器在原始视图控制器(被称为显示中的视图控制器的)和要被显示的新视图控制器(称为被弹出的视图控制器)之间创建关系。 这种关系构成了视图控制器层次结构的一部分,并保持原样直到视图控制器被关闭为止。 ### 弹出和过渡过程 直接弹出视图控制器是一种快速且简单的方法,可以将新内容添加到屏幕上。 内置于 UIKit 中的弹出机制允许您使用内置或自定义动画显示新的视图控制器。 因为 UIKit 处理所有的工作,所以内置的演示和动画只需要很少的代码。只需少许额外的工作, 可以创建自定义弹出效果和动画,并将其用于任何视图控制器。 可以通过编程方式或使用 segue 来初始化视图控制器。 如果在设计时间知道自己的应用导航,那么 segue 初始化弹出效果是最简单的方法。 对于更动态的页面,或者在没有专门的控件来启动 segue 的情况下,使用 UIViewController 的方法来弹出你的视图控制器。 #### 弹出样式 视图控制器的弹出样式控制其在屏幕上的外观。 UIKit 定义了许多标准的弹出样式,每种风格都有特定的外观和用途。 可以定义自己的自定义弹出样式。 在设计应用程序时,请选择正在尝试执行的最适合的弹出样式,并将合适的常量赋值给要弹出的视图控制器的 `modalPresentationStyle` 属性。 #### 全屏弹出样式 全屏弹出样式覆盖整个屏幕,防止与下层内容的交互。在横向的常规环境中,只有一种全屏样式完全覆盖了下层内容。其余样式的内容包含调光或透明度的视图,能显示下层视图控制器的部分视图内容。在水平紧凑的环境中,全屏弹出会自动适应 `UIModalPresentationFullScreen` 风格并覆盖所有下层内容。 图 8-1 显示了在水平常规环境中使用 `UIModalPresentationFullScreen,UIModalPresentationPageSheet 和 UIModalPresentationFormSheet` 样式的直接弹出样式的外观。 在图中,左上方的绿色视图控制器弹出右上角的蓝色视图控制器,每个弹出样式的结果如下所示。 对于某些弹出样式,UIKit 会在两个视图控制器的内容之间插入调光视图。 ###### 图 8-1 全屏弹出样式 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_PresentationStyles%20_fig_8-1_2x.png) > 注意 当使用 `UIModalPresentationFullScreen` 样式弹出视图控制器时,UIKit 通常会在转过渡画完成后删除底层视图控制器的视图。 您可以通过指定 `UIModalPresentationOverFullScreen` 样式来防止删除这些视图。 当弹出的视图控制器具有让底层内容显示的透明区域时,您可以使用该样式。 当使用全屏弹出样式时,调用弹出功能的视图控制器必须覆盖整个屏幕。 如果弹出中的视图控制器没有覆盖屏幕,则 UIKit 遍历控制器层次结构,直到找到一个有效的视图控制器。 如果找不到填充屏幕的中间视图控制器,则 UIKit 将使用窗口的根视图控制器。 #### 弹出窗口的样式 `UIModalPresentationPopover` 样式以弹出窗口的样式显示视图控制器的视图。弹出窗口对于显示附加信息或与光标、选择对象相关的项目列表非常有用。在横向常规环境中,popover 视图只覆盖屏幕的一部分,如图 8-2 所示。在横向紧凑的环境中,弹窗适应 `UIModalPresentationOverFullScreen` 的默认样式。点击弹出窗口外的区域可以自动关闭弹出窗口。 ###### 图 8-2 弹出窗口显示样式 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_popover-style_2x.png) 因为弹出窗口在水平紧凑的环境中适应全屏显示,所以通常需要修改弹出窗口代码来处理适应。在全屏模式下,需要一种方法来关闭显示的弹出窗口。可以通过添加一个按钮,在一个可以关闭的容器视图控制器中嵌入弹窗,或者改变适应行为本身。 有关如何配置弹出窗口显示样式的建议,请参阅 [Presenting a View Controller in a Popover](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW13) 。 #### 当前上下文样式 `UIModalPresentationCurrentContext` 样式覆盖了界面中的特定视图控制器。 使用上下文样式时,通过将其 `defineDesentationContext` 属性设置为 `YES` 来指定要覆盖的视图控制器。 图 8-3 显示了一个当前上下文弹出效果,它只包含一个分割视图控制器的一个子视图控制器。 ###### 图 8-3 当前上下文弹出样式 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_CurrentContextStyles_2x.png) > 注意 当使用 `UIModalPresentationFullScreen` 样式弹出视图控制器时, UIKit 通常会在过渡动画完成后删除底层视图控制器的视图。 您可以通过指定 `UIModalPresentationOverCurrentContext` 样式来防止删除这些视图。 当被弹出的视图控制器具有让底层内容显示的透明区域时,您可以使用该样式。 定义弹出上下文的视图控制器也可以定义在弹出过程中使用的过渡动画。 通常,UIKit 使用被弹出的视图控制器的 `modalTransitionStyle` 属性中的值来在屏幕上动画视图控制器。 如果表示上下文视图控制器将其 `ProvidePresentationContextTransitionStyle` 设置为 YES,则 UIKit 将使用该视图控制器的 `modalTransitionStyle` 属性中的值。 当转换到水平紧凑环境时,当前上下文样式适应 `UIModalPresentationFullScreen` 样式。 要更改该行为,请使用自适应表示委托来指定不同的弹出样式或视图控制器。 #### 自定义弹出样式 `UIModalPresentationCustom` 风格允许使用定义的自定义样式弹出视图控制器。 创建自定义样式涉及到 `UIPresentationController` 的子类化,并使用其方法来将任何自定义视图动画到屏幕上,并设置弹出的视图控制器的大小和位置。 弹出控制器还处理由于所弹出的视图控制器的特性的变化而发生的任何改动。 有关如何定义自定义弹出控制器的信息,请参阅 [Creating Custom Presentations](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/DefiningCustomPresentations.html#//apple_ref/doc/uid/TP40007457-CH25-SW1) 。 #### 过渡样式 过渡样式决定用于显示呈现的视图控制器的动画类型。 对于内置过渡样式,可以将其中一种标准过渡样式分配给要呈现的视图控制器的 `modalTransitionStyle` 属性。弹出视图控制器时,UIKit 会创建与该样式相对关的动画。例如,图 8-4 说明了标准的从下弹出过渡样式(UIModalTransitionStyleCoverVertical)如何用动画方式将视图控制器显示在屏幕上。 视图控制器 B 从屏幕下边开始并且在视图控制器 A 的上一层进行动画。当视图控制器 B 被关闭时,动画反转,以便 B 向下滑动以显示 A . ###### 图 8-4 视图控制器的过渡动画 ![](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/Art/VCPG_SlideTransition_fig_8-1_2x.png) 可以使用 animator 对象和 transitioning delegate 建自定义转场。 animator 对象创建用于将视图控制器置于屏幕上的过渡动画。 transitioning delegate 在适当的时候将 animator 对象提供给 UIKit 。 有关如何实现自定义转场的信息,请参阅[ Customizing the Transition Animations](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html#//apple_ref/doc/uid/TP40007457-CH16-SW1) 。 #### 弹出和显示视图控制器对比 UIViewController 提供了两种显示视图控制器的方法: ~~~ - (void)showViewController:(UIViewController *)vc sender:(id)sender; - (void)showDetailViewController:(UIViewController *)vc sender:(id)sender; ~~~ * 这倆方法为显示视图控制器提供了最合适和最灵活的方式。这些方法让显示中的视图控制器决定如何最好地处理弹出效果。例如,容器视图控制器可以将视图控制器作为一个子节点,而不是以弹出方式呈现。默认行为以弹出方式呈现视图控制器。 * ` presentViewController:animated:completion: ` 默认以弹出方式显示视图控制器。 调用此方法的视图控制器可能最终不处理弹出过程,但默认是弹出。 这种方法适合水平紧凑环境的显示风格。` showViewController:sender:` 和 ` showDetailViewController:sender:` 方法是初始化弹出效果的首选方式。视图控制器可以在不知道视图控制器层次结构的其他部分或当前视图控制器在该层次结构中的位置的情况下调用它们。这些方法也使得在应用程序的不同部分重用视图控制器变得更加容易,而无需编写有条件的代码路径。 ### 弹出视图控制器 有几种方法可以启动视图控制器的显示: * 使用 segue 自动显示视图控制器。 segue 使用您在 Interface Builder 中指定的信息来实例化并呈现视图控制器。 有关如何配置 segues 的更多信息,请参阅使用 [Segues](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html#//apple_ref/doc/uid/TP40007457-CH15-SW1)。 * 使用 `showViewController:sender:` 或 `showDetailViewController:sender:` 方法来显示视图控制器。 在自定义视图控制器中,您可以将这些方法的显示效果更改为更适合您的视图控制器的显示效果。 * 调用 `presentViewController:animated:completion:` 方法以弹出方式呈现视图控制器。 有关如何关闭使用其中一种技巧呈现的视图控制器的信息,请参阅 [Dismissing a Presented View Controller](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW10) 。 #### 显示视图控制器 当使用 `showViewController:sender:` 或 `showDetailViewController:sender:` 方法时,创建新视图控制器并在屏幕上显示的过程很简单: 1. 创建想要呈现的视图控制器对象。 在创建视图控制器时,使用执行其任务需要的数据对其进行初始化 2. 将新视图控制器的 `modalPresentationStyle` 属性设置为需要的样式。 这种样式可能不会在最后的显示过程中使用 3. 将视图控制器的 `modalTransitionStyle` 属性设置为所需的过渡动画样式。 这种样式可能不会用在最后的动画中 4. 调用当前视图控制器的 `showViewController:sender:` 或 `showDetailViewController:sender:` 方法 UIKit 将调用`showViewController:sender:` 或 `showDetailViewController:sender:` 方法转发给相应的当前显示中的视图控制器。 该视图控制器可以决定如何最好地执行显示效果,并可以根据需要更改显示样式和转换样式。 例如,导航控制器可能会将视图控制器推到其导航堆栈上。 有关显示视图控制器和以模态方式显示视图控制器之间的区别的信息,请参 [Presenting Versus Showing a View Controller](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW4) 。 #### 以弹出方式显示视图控制器 当直接弹出视图控制器时,您告诉 UIKit 如何显示新的视图控制器以及如何在屏幕上显示动画: 1. 创建想要呈现的视图控制器对象。 在创建视图控制器时,使用执行其任务需要的数据对其进行初始化 2. 将新视图控制器的 `modalPresentationStyle` 属性设置为需要的样式 3. 将视图控制器的 `modalTransitionStyle` 属性设置为所需的过渡动画样式 4. 调用当前视图控制器的 `presentViewController:animated:completion:` 方法。 调用 `presentViewController:animated:completion:` 方法的视图控制器可能不是实际执行弹出显示效果的视图控制器。显示样式确定如何呈现视图控制器,包括当前显示中的视图控制器所需的特殊属性。例如,全屏显示必须由全屏视图控制器启动。如果当前呈现的视图控制器不合适, UIKit 将遍历视图控制器层次结构,直到找到一个为止。UIKit 在完成弹出显示后,会更新受影响视图控制器的 `presentsViewController` 和 `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]; } ~~~ #### 在弹出窗口中显示视图控制器 弹出窗口需要额外的配置,才能呈现它们。设置 `modalPresentationStyle` 为 `UIModalPresentationPopover` 后,配置以下相关属性: * 将视图控制器的 `preferredContentSize` 属性设置为所需的大小 * 使用可从视图控制器的 `popoverPresentationController` 属性设置弹出窗口锚点 * 设置 `barButtonItem` 属性 * 将 `sourceView` 和 `sourceRect` 属性设置为某个视图中的特定区域。 可以使用 UIPopoverPresentationController 对象根据需要对弹出窗口的外观进行其他调整。 弹窗显示视图控制器还支持可用于在弹出过程中响应更改的委托对象。 例如,当弹出窗口出现,消失或在屏幕上重新定位时,可以使用委托进行响应。有关此对象的更多信息,请参阅 [UIPopoverPresentationController Class Reference](https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller) 。 ### 关闭一个显示的视图控制器 要关闭一个弹出的视图控制器,请调用显示中的视图控制器的 `dismissViewControllerAnimated:completion:` 方法。 也可以在弹出的视图控制器本身上调用此方法。 当在弹出的视图控制器上调用该方法时,UIKit 会自动将该请求转发给显示中视图控制器。 在关闭视图控制器之前,保存视图控制器中的重要信息。 关闭视图控制器会将其从视图控制器层次结构中删除,并将其视图从屏幕上移除。 如果没有强引用来存储视图控制器,关闭它将释放与之关联的内存。 如果弹出的视图控制器必须将数据返回给显示中的视图控制器,则使用委托设计模式来传输。 委托可以更轻松地在应用程序的不同部分重用视图控制器。 通过委托,弹出的视图控制器存储了一个遵守并实现协议中方法的委托对象的引用。 当收集结果时,弹出的视图控制器在其委托上调用这些方法。 在一个典型的实现中,显示中的视图控制器使自己成为弹出的视图控制器的委托对象。 ### 在不同的 Storyboard 中弹出一个视图控制器 虽然可以在同一个故事板中的视图控制器之间创建 segues,但不能在故事板之间创建 segues 。当你想显示一个存储在不同故事板中的视图控制器时,你必须在显示它之前明确地实例化这个视图控制器,如清单 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 。