场景问题
单个 View 上可能存在多个按钮,各自需要弹出不同内容的 sheet;若用多个 sheet(isPresented:) 修饰符,会导致:
- 运行时顺序不确定
- 状态管理分散
- 难以扩展
SwiftUI 提供 “单源真值” 方案:使用 sheet(item:) 一次声明、按需弹出。
最佳实践步骤
- 定义统一数据模型,遵循
Identifiable:
struct RandomModel: Identifiable {
let id = UUID().uuidString
let title: String
}
- 用一个可选状态管理所有弹窗:
@State private var selectedModel: RandomModel? = nil
- 在根视图单次声明
sheet(item:):
var body: some View {
VStack(spacing: 8) {
Button("Button #1") {
selectedModel = RandomModel(title: "ONE")
}
Button("Button #2") {
selectedModel = RandomModel(title: "TWO")
}
}
.sheet(item: $selectedModel) { model in // ← 只写一次
NextScreen(selectedModel: model)
}
}
- 弹窗内拿到值类型即可使用,无需再传
Binding:
struct NextScreen: View {
let selectedModel: RandomModel
var body: some View {
Text(selectedModel.title)
.font(.largeTitle)
}
}
优势
- 单一状态源,逻辑清晰
- 自动管理生命周期(nil → 关,非 nil → 开)
- 支持动画、链式回调与锚点定位
- 易扩展:新增按钮只需赋值同一状态,无需追加修饰符
注意事项
- 模型必须遵循
Identifiable;若用Int序号,可用.id(.self)显式标记。 - 避免在
sheet(item:)后再挂sheet(isPresented:),否则弹出顺序不可控。 - 弹窗内部如需修改外部状态,使用
Environment(.dismiss)或回调闭包,而非额外Binding。