UIModalPresentationStyle 各种类型的区别

17,300 阅读3分钟

UIViewController有个属性modalPresentationStyle,它决定了当前控制器 present 出的下一控制器的展示方式。

官方文档对这些效果有比较详细的介绍,这里写个 demo 帮助理解,demo 在模拟器上运行可能会有一点卡顿,真机没有影响。

预备知识

presenting、presented viewController

presentingViewController指的是 present 出当前控制器的控制器。

presentedViewController指被当前控制器 present 出的控制器。

Size Class

对于各种常见情况的 Size Class 如下几张图片所示:

iPhonePlus的SizeClass
iPhonePlus的SizeClass

普通iPhone的SizeClass
普通iPhone的SizeClass

全屏iPad的SizeClass
全屏iPad的SizeClass

UIModalPresentationStyle

enum UIModalPresentationStyle : Int {
    case fullScreen
    case pageSheet
    case formSheet
    case currentContext
    case custom
    case overFullScreen
    case overCurrentContext
    case popover
    case none
}

fullScreen

  • 在各种 Size Class 情况下都是全屏展示
  • 执行 present 操作的控制器的view和它的subViews,在 present 完成后都会被从当前视图层级移除

fullScreen
fullScreen

对于水平方向为 compact 的情况,不管用哪种 style 推出其他控制器,presentedViewController都是以fullScreen方式展示。所以剩下的所有类型,都只针对水平方向为 regular 论述。

pageSheet

  • 被推出视图部分的遮盖下层视图
  • 其宽度总是为该设备竖屏时候的宽度(不可变),高度则为当前设备方向的屏幕高度(可变,其实还要去掉状态栏的高度)

pageSheet竖屏
pageSheet竖屏

pageSheet横屏
pageSheet横屏

formSheet

  • 被推出视图大小比屏幕的小,且总是居中显示
  • 在横屏时,如果弹出了键盘,视图位置会跟着上移
  • 可以设置被推出视图的preferredContentSize来设置它的大小

formSheet竖屏
formSheet竖屏

formSheet横屏
formSheet横屏

这里设置了preferredContentSize = CGSize(width: 200, height: 200)

currentContext

  • 可以用在 iPadUISplitViewController中,指定单独覆盖屏幕单侧的控制器;popover方式展示的控制器,再用该方式 present 出下一视图
  • 在执行 present 操作的控制器的控制器层级中往上查找,如果某个控制器的definesPresentationContext == true则它来 present,假如没有一个为true,那么则由 window.rootController来 present
  • 执行 present 操作的控制器的view和它的subViews,在 present 完成后都会被从当前视图层级移除

definesPresentationContext默认为false,系统提供的一些像UINavigationController的控制器,其默认值为true。它的定义为:

A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.

对于以currentContext方式推出的视图,如果它的presentedViewController是一个popover,那么推出该视图的modalTransitionStyle不能是partialCurl,否则会引起崩溃。

currentContext竖屏
currentContext竖屏

currentContext横屏
currentContext横屏

currentContextInPopover
currentContextInPopover

custom

A custom view presentation style that is managed by a custom presentation controller and one or more custom animator objects.

详细介绍在下篇文章中进行。

overFullScreen

基本和fullScreen一致。只是 present 完成后,不会移除执行 present 操作的控制器的view和它的subViews。如果presentedViewController.view是有透明度的,底层视图就可以得以显示。

overFullScreen
overFullScreen

overCurrentContext

基本和currentContext一致。只是 present 完成后,不会移除执行 present 操作的控制器的view和它的subViews。如果presentedViewController.view是有透明度的,底层视图就可以得以显示。

overCurrentContext
overCurrentContext

popover

  • 在 iPad 上用popover的方式显示;在 iPhone 上默认用fullScreen方式显示,但是在 iOS8 后可以设置成popover的方式,在none中会进行解释
  • 默认情况下,点击灰色的背景popover会直接消失,通过presentedViewController.popoverPresentationController?.passthroughViews可以配置灰色背景的哪些视图区域可以点击

UIPopoverPresentationController的定义:

An object that manages the display of content in a popover.

当视图被用popover方式 present 的时候,总有一个popoverPresentationController的实例来管理呈现的行为。

popover
popover

none

  • 该枚举值不可以直接赋值给modalPresentationStyle
  • popoverPresentationController会调用它delegate的方法来配置popover的视图,none只能用在adaptivePresentationStyle(for:)代理方法中返回,告诉popoverPresentationController不要适配presentedViewController,这样在 iPhone 中也可以用popover的样式展示了

none
none