如何通过确认弹窗控制SwiftUI Sheet的滑动关闭行为
解决SwiftUI Sheet下滑关闭时的确认弹窗问题
要实现Sheet下滑关闭时弹出确认弹窗(而非直接阻止),核心思路是自定义绑定拦截Sheet的关闭请求,结合未保存状态判断是否触发确认弹窗。以下是完整实现方案:
步骤1:添加状态变量
新增跟踪表单输入和未保存状态的变量:
name:绑定到TextField的输入值,替换原来的.constanthasUnsavedChanges:判断是否存在未保存的修改
步骤2:创建自定义绑定
通过自定义Binding<Bool>拦截Sheet的关闭请求:当用户尝试关闭(包括下滑和Cancel按钮点击)时,先检查是否有未保存更改,有则弹出确认弹窗,无则直接关闭。
完整代码实现
struct ContentView: View { @State var showSheet = false @State var showConfirmation = false @State var name = "Hello, World." // 替换constant,绑定输入框 @State var hasUnsavedChanges = false // 自定义绑定,拦截Sheet关闭请求 private var sheetBinding: Binding<Bool> { Binding( get: { showSheet }, set: { newValue in guard !newValue else { showSheet = true return } // 用户尝试关闭Sheet,检查未保存状态 if hasUnsavedChanges { showConfirmation = true } else { showSheet = false } } ) } var body: some View { Form { Button("Show Sheet") { showSheet = true } } .sheet(isPresented: sheetBinding) { // 使用自定义绑定 NavigationStack { Form { TextField("Name", text: $name) .onChange(of: name) { newValue in // 对比初始值,更新未保存状态 hasUnsavedChanges = newValue != "Hello, World." } } .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { // 点击Cancel时触发自定义绑定的关闭逻辑 showSheet = false } } } .confirmationDialog("是否放弃更改?", isPresented: $showConfirmation) { Button("放弃更改", role: .destructive) { showSheet = false } Button("取消", role: .cancel) {} } // 移除interactiveDismissDisabled(),让下滑关闭触发绑定逻辑 } } } }
关键说明
- 自定义绑定的作用:无论用户通过下滑还是Cancel按钮关闭Sheet,都会触发绑定的
set方法,统一处理关闭逻辑,避免重复代码。 - 未保存状态判断:通过
onChange监听输入框值的变化,对比初始值来更新hasUnsavedChanges,确保仅在有修改时才弹出确认。 - 确认弹窗完善:添加了「取消」按钮,让用户可以放弃关闭操作,回到表单页面。
内容的提问来源于stack exchange,提问作者Sheffield
相关产品推荐
相关产品推荐

