在Swift中,sheet 是一个用于显示模态视图(Modal View)的功能,通常在SwiftUI框架中使用。模态视图是一个临时的、覆盖在主界面上的视图,用户需要完成某些任务或交互后才能返回主视图。
基本用法
sheet 是一个视图修饰符,绑定到一个布尔值或可选值,当条件满足时,会呈现一个模态视图。
基本语法:
.sheet(isPresented: $isSheetPresented) {
// 显示的内容
YourView()
}
示例:
import SwiftUI
struct ContentView: View {
@State private var isSheetPresented = false
var body: some View {
VStack {
Button("显示模态视图") {
isSheetPresented = true
}
}
.sheet(isPresented: $isSheetPresented) {
Text("这是一个模态视图")
.font(.largeTitle)
}
}
}
使用可选值触发
也可以使用sheet(item:binding:),当一个可选值(如Optional)不为nil时,显示模态视图。
示例:
struct Item: Identifiable {
let id = UUID()
let name: String
}
struct ContentView: View {
@State private var selectedItem: Item? = nil
var body: some View {
VStack {
Button("选择项目") {
selectedItem = Item(name: "示例项目")
}
}
.sheet(item: $selectedItem) { item in
Text("选中了: \(item.name)")
.font(.title)
}
}
}
模态视图的自定义
模态视图可以包含复杂的UI,甚至嵌套其他视图。
示例:复杂模态视图
struct someView: View {
@State private var isSheetPresented = false
var body: some View {
VStack {
Button("打开模态视图") {
isSheetPresented = true
}
}
.sheet(isPresented: $isSheetPresented) {
ModalView()
}
}
}
struct ModalView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Text("这是一个模态视图")
.font(.headline)
Button("关闭") {
dismiss()
// 通常由父视图的绑定控制关闭逻辑
// 在实际项目中,这个按钮的动作会回调父视图的状态更新
}
}
}
}
模态视图关闭
在SwiftUI中,模态视图的关闭通常由绑定的状态值(如isPresented)控制。当需要手动关闭模态视图时,可以直接修改绑定值。例如,将isSheetPresented设为false。
示例:
struct ContentView: View {
@State private var isSheetPresented = false
var body: some View {
VStack {
Button("显示模态视图") {
isSheetPresented = true
}
}
.sheet(isPresented: $isSheetPresented) {
VStack {
Text("这是一个模态视图")
.font(.largeTitle)
Button("关闭") {
isSheetPresented = false
}
}
}
}
}
onDismiss参数
在 SwiftUI 中,onDismiss: 是一个参数,用于在 sheet 模态视图被关闭时触发某个操作。具体来说,onDismiss:表示当sheet的模态视图被关闭时,会自动调用其方法。
示例代码:
.sheet(isPresented: $showingEditScreen, onDismiss: resetCards) {
EditCards()
}
onDismiss: resetCards: 当 EditCards 被关闭(例如用户手动滑下关闭)时,会调用 resetCards()。
为什么需要 onDismiss?
可能希望在模态视图关闭后执行某些动作,例如:
刷新数据。
重置某些状态。
保存或清理用户输入。
小结
onDismiss: 的作用是 在模态视图关闭时触发重置动作,以保证应用的状态与预期一致。这种方式可以很好地维护界面逻辑的流畅性,避免用户的操作或数据遗漏引发问题。
Init()初始化器
1、.sheet() 的正常用法
通常,.sheet() 的 content 参数 需要一个闭包,该闭包返回一个视图。
例如:
.sheet(isPresented: $showingEditScreen, onDismiss: resetCards) {
EditCards()
}
在这里,{ EditCards() } 是一个闭包,它返回 EditCards 视图的实例。
2、Swift 的“语法糖”
EditCards() 实际上是使用了 Swift 的语法糖,它等同于调用 EditCards 的初始化器 EditCards.init(),因为 EditCards 是一个结构体,其默认初始化器 init() 可以用来创建实例。
所以,以下两种写法是等效的:
EditCards()
EditCards.init()
3、优化写法
既然 EditCards() 是初始化器 EditCards.init() 的简写,content: 参数本质上需要的是一个返回视图的函数,我们就可以直接将初始化器 EditCards.init 作为参数传递,而不需要额外的闭包包装。
.sheet(isPresented: $showingEditScreen, onDismiss: resetCards) {
EditCards()
}
可以简化成这样:
.sheet(isPresented: $showingEditScreen, onDismiss: resetCards, content: EditCards.init)
在这个写法中:
EditCards.init 是初始化器的引用,SwiftUI 会自动调用它来创建 EditCards 视图。
4、为什么可以直接使用初始化器?
在 Swift 中,初始化器(init)本质上是一个特殊的函数,可以被传递或调用。.sheet() 的 content 参数需要一个返回视图的函数,而 EditCards.init 完全符合这个要求。
注意事项
1、仅限一次显示一个模态视图: 如果试图同时触发多个sheet,SwiftUI会根据条件的先后显示一个。
2、支持动画过渡: sheet的展示和关闭具有默认的过渡动画。
3、与NavigationView的交互: 模态视图内部可以使用NavigationView实现导航功能。
扩展知识
presentationDetents修饰符
如果想要自定义弹出的Sheet尺寸,可以使用presentationDetents修饰符。
.sheet(isPresented: $isPresented) {
Text("This is a sheet")
.presentationDetents([.medium, .large])
}
presentationDetents([.medium, .large]): 设置弹出的 Sheet 可以在 中等高度 和 全屏高度 之间切换。
.medium 和 .large 是预定义的高度类型。
相关知识可以了解《SwiftUI自定义弹出的Sheet的尺寸》
相关文章
Sheet嵌套Sheet页返回问题:https://fangjunyu.com/2024/10/19/swift-%e5%b5%8c%e5%a5%97sheet%e9%a1%b5%e8%bf%94%e5%9b%9e%e9%97%ae%e9%a2%98/