#7 Multiple Sheets

2 阅读1分钟

场景问题

单个 View 上可能存在多个按钮,各自需要弹出不同内容的 sheet;若用多个 sheet(isPresented:) 修饰符,会导致:

  • 运行时顺序不确定
  • 状态管理分散
  • 难以扩展

SwiftUI 提供 “单源真值” 方案:使用 sheet(item:) 一次声明、按需弹出。

最佳实践步骤

  1. 定义统一数据模型,遵循 Identifiable
struct RandomModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}
  1. 一个可选状态管理所有弹窗:
@State private var selectedModel: RandomModel? = nil
  1. 在根视图单次声明 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)
    }
}
  1. 弹窗内拿到值类型即可使用,无需再传 Binding
struct NextScreen: View {
    let selectedModel: RandomModel
    var body: some View {
        Text(selectedModel.title)
            .font(.largeTitle)
    }
}

优势

  • 单一状态源,逻辑清晰
  • 自动管理生命周期(nil → 关,非 nil → 开)
  • 支持动画、链式回调与锚点定位
  • 易扩展:新增按钮只需赋值同一状态,无需追加修饰符

注意事项

  1. 模型必须遵循 Identifiable;若用 Int 序号,可用 .id(.self) 显式标记。
  2. 避免在 sheet(item:) 后再挂 sheet(isPresented:),否则弹出顺序不可控。
  3. 弹窗内部如需修改外部状态,使用 Environment(.dismiss) 或回调闭包,而非额外 Binding