Full Screen Cover — iOS 中的一种模态展示风格,新屏幕占据整个显示屏,父级内容不可见。与 Page Sheet 不同,Full Screen Cover 完全隐藏前一屏幕,用于媒体内容、照片编辑器和授权屏幕。根据 Apple Developer, 2025,这种风格在 iOS 13 之前是默认的,但在沉浸式场景中仍然是首选。在 SwiftUI 中,.fullScreenCover 修饰符提供了全屏展示的声明式 API。
要点
Full Screen Cover — 是 iOS 中的一种模态展示风格,被展示的控制器占据设备的整个屏幕。父级内容被完全隐藏,营造沉浸式效果,使用户专注于当前任务。
在 iOS 13 之前,Full Screen Cover 是 iPhone 上唯一的模态展示风格。所有 present(_:animated:completion:) 调用默认使用 .fullScreen。从 iOS 13 开始,Apple 将默认风格改为 .automatic,对于 iPhone 选择 .pageSheet。然而,Full Screen Cover 仍然可用,并用于需要完全专注的场景。
与 Page Sheet 不同,Full Screen Cover 不允许与父级内容交互,也不在模态窗口下方显示父级内容。用户无法通过向下滑动来关闭 Full Screen Cover — 关闭需要程序化调用 dismiss(animated:completion:) 或屏幕本身的关闭按钮。这种在设计 UX 时需要重要考虑。
Page Sheet — 第二种主要模态展示风格,在 iOS 13 中出现。Page Sheet 以卡片形式显示,顶部有间距,下方可看到父级屏幕。用户可以通过向下滑动关闭 Page Sheet。Full Screen Cover 则相反,隐藏父级内容且不支持滑动关闭。
| 特性 | Full Screen Cover | Page Sheet |
|---|---|---|
| 背景覆盖 | 完全,父级内容不可见 | 部分,父级在卡片下方可见 |
| 滑动关闭 | 否,仅程序化或通过按钮 | 是,向下滑动关闭 |
| 典型应用 | 视频、相机、照片编辑器、PDF | 表单、设置、详细查看 |
| 显示动画 | 从下往上,全屏 | 从下往上,带间距的卡片 |
| 可用性 | iOS 2+ | iOS 13+ |
选择 Full Screen Cover 还是 Page Sheet 取决于内容和上下文。建议对需要完全注意力的内容使用 Full Screen Cover:全屏模式视频、照片预览、文档扫描。Page Sheet — 用于父级屏幕上下文重要的任务:编辑表单、选项选择、查看详情。
UIKit 提供 UIModalPresentationStyle.fullScreen 常量用于配置模态展示风格。在调用 present 之前在 UIViewController 上设置此属性可确保控制器全屏显示。控制器还管理键盘出现时的行为和系统事件的处理。
设置 .fullScreen 风格后,建议配置 presentationController?.delegate 来处理关闭事件。UIAdaptivePresentationControllerDelegate 代理允许拦截关闭尝试并防止数据丢失。与 Page Sheet 不同,对于 Full Screen Cover,代理仅在程序化 dismiss 调用时触发。
Full Screen Cover 正确处理屏幕旋转和键盘出现。旋转时,模态控制器自动适应新方向。UIKeyboardWillShowNotification 允许在键盘出现时将内容上移,使文本字段保持可见。与 Page Sheet 不同,Full Screen Cover 在键盘出现时不改变尺寸。
let playerVC = VideoPlayerViewController()
playerVC.modalPresentationStyle = .fullScreen
playerVC.modalTransitionStyle = .crossDissolve
present(playerVC, animated: true) {
playerVC.startPlayback()
}
// 关闭
dismiss(animated: true) {
print("播放器已关闭")
}
SwiftUI 提供 .fullScreenCover 修饰符用于声明式创建全屏模态窗口。与 .sheet(Page Sheet)不同,.fullScreenCover 创建 .fullScreen 风格,行为类似:完全覆盖内容且不支持滑动关闭。
修饰符接受 Bool 类型的 binding 或可选的可识别对象。当 binding 设置为 true 时,SwiftUI 动画显示全屏窗口。数据传递使用 onDismiss 参数和包含内容的闭包。环境值 \.dismiss 允许从内部关闭模态窗口。
在 SwiftUI 中选择 .fullScreenCover 和 .sheet 类似于 UIKit:.fullScreenCover 用于沉浸式内容,.sheet 用于卡片。SwiftUI 自动选择正确的关闭行为:.sheet 可以通过滑动关闭,.fullScreenCover — 只能程序化关闭。修饰符可以在同一 View 层次结构中组合使用。
struct CameraView: View {
@State private var showCamera = false
var body: some View {
Button("打开相机") {
showCamera = true
}
.fullScreenCover(isPresented: $showCamera) {
CameraPreviewView()
.ignoresSafeArea()
}
}
}
struct CameraPreviewView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
VStack {
Spacer()
Button("拍摄") { dismiss() }
.foregroundColor(.white)
}
}
}
}
Full Screen Cover 支持通过 UIModalTransitionStyle 在 UIKit 中实现自定义动画,以及在 SwiftUI 中实现自定义过渡。标准样式:.coverVertical(从下往上)、.crossDissolve(逐渐显示)、.flipHorizontal(翻转)和 .partialCurl(翻页效果)。
对于完全自定义动画,实现 UIViewControllerAnimatedTransitioning 协议。它允许通过 animateTransition(using:) 方法定义动画持续时间和过渡本身。动画控制器通过 UINavigationControllerDelegate 或 UIViewControllerTransitioningDelegate 代理指定。
在 SwiftUI 中,.fullScreenCover 的自定义过渡通过 matchedGeometryEffect 创建。此修饰符动画化元素从父级 View 到全屏窗口的移动。例如,点击照片缩略图时,它会平滑展开到全屏,产生连续性效果。MatchedGeometryEffect 使用 id 和 namespace,将元素在源位置和目标位置连接起来。
struct PhotoViewer: View {
@State private var selectedPhoto: String?
@Namespace private var animation
var body: some View {
HStack {
ForEach(["photo1", "photo2"], id: \.self) { photo in
Image(photo)
.matchedGeometryEffect(id: photo, in: animation)
.onTapGesture { selectedPhoto = photo }
}
}
.fullScreenCover(item: $selectedPhoto) { photo in
Image(photo)
.matchedGeometryEffect(id: photo, in: animation)
.ignoresSafeArea()
}
}
}
Full Screen Cover 建议用于内容应占据整个屏幕而不受父级界面干扰的场景。Apple HIG 区分了三个主要类别:媒体内容、内容创建工具和临时系统界面。
视频播放器、照片查看、阅读 PDF 和漫画 — Full Screen Cover 的典型使用示例。AVPlayerViewController 在 iOS 中切换到横屏时自动使用全屏模式。Adobe Lightroom 等照片编辑器在图像库上方打开全屏编辑器。
相机、文档扫描仪、录音 — 需要用户全神贯注的任务。UIImagePickerController 在 iOS 14 之前对相机使用 Full Screen Cover。从 iOS 14 开始,系统选择器使用 Page Sheet,但开发人员可以为自定义相机强制设置 .fullScreen。
不要对以下情况使用 Full Screen Cover:注册表单(优先选择 Page Sheet)、父级页面上下文重要的文本输入屏幕以及模态窗口内的连续导航。Material Design 也建议避免阻止系统返回按钮 — 在 iOS 中这是允许的,但用户应该通过界面元素有明确的关闭方式。
常见问题
.fullScreen 隐藏父级控制器并将其从显示层次结构中移除。.overFullScreen 在父级之上显示模态控制器,但父级保留在层次结构中并继续接收事件。overFullScreen 适用于透明背景和自定义图层动画。
Apple 在 iOS 13 中更改了默认风格以改善用户交互。Page Sheet 允许查看父级屏幕的上下文并通过滑动关闭模态窗口,从而加快导航速度。Full Screen Cover 保留用于需要完全专注而不受背景干扰的场景。
在 UIKit 中,在 presentingViewController 或 presentedViewController 上调用 dismiss(animated:completion:)。在 SwiftUI 中,使用环境值 \.dismiss 并将其作为函数调用。要从父级控制器以编程方式关闭,将传递给 .fullScreenCover 的 binding 改为 false。
是的,Full Screen Cover 可以在 iPad 上使用。iPad 还支持其他样式:.formSheet(固定大小的居中窗口)和 .currentContext(相对于父级控制器)。在 iPad 上,如果未强制设置 modalPresentationStyle,Full Screen Cover 可能看起来像 Page Sheet。
与 Page Sheet 不同,Full Screen Cover 不会通过滑动关闭,因此数据丢失仅发生在程序化 dismiss 时。重写 dismiss(animated:completion:) 方法或使用在关闭前调用的 UIAdaptivePresentationControllerDelegate。显示带有选项的 UIAlertController:保存、取消或停留在屏幕。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。