在 SwiftUI 中,有许多展示视图的方法,而其中一种最基本的方式就是使用 sheet:在现有视图上展示一个新视图。在 iOS 上,这种展示方式会自动呈现为类似卡片的形式,当前视图稍微向后滑动,而新视图则动画地从底部滑入。
与警报 (alert) 类似,sheet 的展示并不是通过代码直接调用 mySheet.present()
等方法来完成的,而是通过定义一个条件,当条件为 true
时,sheet 被展示;当条件为 false
时,sheet 被关闭。
我们从一个简单的例子开始,展示如何通过 sheet 在一个视图中展示另一个视图。首先,创建我们想要在 sheet 中显示的视图:
struct SecondView: View {
var body: some View {
Text("Second View")
}
}
这只是一个简单的视图,SecondView 不需要知道自己会在一个 sheet 中展示。
接下来,我们在主视图中创建一个按钮,点击该按钮后展示 SecondView:
struct ContentView: View {
var body: some View {
Button("Show Sheet") {
// show the sheet
}
}
}
为了让这个按钮能够展示 sheet,我们需要完成以下四个步骤:
我们可以使用一个布尔值来标记当前是否展示 sheet。将以下属性添加到 ContentView
:
@State private var showingSheet = false
我们需要在按钮点击时切换 showingSheet
的值。替换掉注释部分,代码变为:
showingSheet.toggle()
接下来,我们需要将 sheet 附加到视图层级上。类似于警报使用 isPresented
绑定状态属性,我们可以使用 sheet(isPresented:)
来实现:
.sheet(isPresented: $showingSheet) {
// contents of the sheet
}
我们知道,sheet 的内容就是我们刚才创建的 SecondView
。所以在 sheet
的闭包中,我们创建并展示一个 SecondView()
实例:
struct ContentView: View {
@State private var showingSheet = false
var body: some View {
Button("Show Sheet") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
SecondView()
}
}
}
运行程序后,你将能够点击按钮,在底部滑动显示 SecondView,并且可以通过拖动来关闭这个 sheet。
如果你希望在 SecondView
中显示一些动态内容,可以给它传递数据。例如,SecondView
需要显示一个名字:
struct SecondView: View {
let name: String
var body: some View {
Text("Hello, \(name)!")
}
}
现在,直接使用 SecondView()
在 sheet 中展示是不行的,因为我们需要为它传递一个名字。你可以这样传递数据:
.sheet(isPresented: $showingSheet) {
SecondView(name: "@twostraws")
}
这将使得 SecondView
显示 “Hello, @twostraws”。
Swift 的类型系统非常强大,它会确保你传递给 SecondView
的数据类型是正确的。如果你在没有传递 name
时尝试使用 SecondView()
,编译器会直接报错,确保我们没有遗漏必要的参数。
到目前为止,用户可以通过向下滑动来关闭 sheet。但有时候,你可能希望通过代码来关闭 sheet,比如点击按钮时自动关闭。
要实现这一点,我们需要使用 @Environment 属性包装器。这个包装器让我们能够访问外部环境提供的值。例如,是否使用暗黑模式、字体大小的设置等等。在这里,我们将利用它来获取用于关闭视图的方法。
为了实现程序化关闭,我们需要在 SecondView 中添加以下代码:
@Environment(\.dismiss) var dismiss
然后,将 SecondView 中的文本视图替换为一个按钮,点击时关闭当前视图:
Button("Dismiss") {
dismiss()
}
现在,当你点击按钮时,sheet 将会被关闭。
通过使用 sheet 和 @State,你可以轻松地在 SwiftUI 中展示和关闭视图。同时,通过 @Environment(.dismiss) 可以程序化地关闭视图,提供了更灵活的用户交互方式。