iPad端SwiftUI中Sheet内ColorPicker的关闭异常问题
SwiftUI iPad端Sheet内ColorPicker的关闭异常问题
问题现象
- 仅在iPad端出现该问题,iPhone和Mac端运行正常
- 操作流程:在Sheet内打开ColorPicker选择颜色时,未关闭Picker弹窗就点击Sheet的「Cancel」关闭按钮,此时
dismiss()仅关闭ColorPicker弹窗而非Sheet - 后续异常:ColorPicker关闭后,Sheet的「Cancel」按钮完全失效,只能通过点击Sheet外部区域关闭Sheet
问题原因
iPad上的ColorPicker默认以popover形式展示,当它处于打开状态时,会成为当前层级最高的presentation容器,此时调用dismiss()会优先关闭这个popover,而非底层的Sheet。popover关闭后,Sheet的dismiss绑定出现异常,导致按钮失效。
解决方案
通过手动控制ColorPicker的popover显示状态,在点击Sheet的「Cancel」按钮时,先关闭ColorPicker的popover,再关闭Sheet。具体实现步骤如下:
- 给Detail视图添加状态变量,控制ColorPicker的popover显示/隐藏
- 将原生ColorPicker改为通过Button触发自定义popover的形式
- 在「Cancel」按钮的点击事件中,先检查ColorPicker是否打开,若打开则先关闭它,延迟片刻后再调用
dismiss()关闭Sheet(延迟是为了确保popover完全关闭,避免层级冲突)
修改后的示例代码
@available(iOS 16.0, *) struct Pruebas: View { @State private var showSheet: Bool = false var body: some View { Button("Show") { showSheet.toggle() } .sheet(isPresented: $showSheet) { Detail() } } } @available(iOS 16.0, *) struct Detail: View { @Environment(\.dismiss) var dismiss @State private var color: Color = .orange @State private var isColorPickerPresented = false // 手动控制ColorPicker弹出状态 var body: some View { NavigationStack { VStack { // 自定义触发按钮,控制ColorPicker的popover Button("选择颜色") { isColorPickerPresented.toggle() } .popover(isPresented: $isColorPickerPresented) { ColorPicker("选择颜色", selection: $color) .padding() .presentationCompactAdaptation(.popover) // 强制iPad上使用popover样式 } .padding() // 预览选中的颜色 color.frame(width: 100, height: 100) .cornerRadius(8) } .navigationTitle("颜色选择") .toolbar { Button("Cancel") { if isColorPickerPresented { // 先关闭ColorPicker的popover isColorPickerPresented = false // 延迟执行Sheet的dismiss,确保popover完全关闭 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { dismiss() } } else { dismiss() } } } } } }
补充说明
如果不想自定义触发按钮,也可以通过@FocusState控制ColorPicker的焦点状态,在点击Cancel时先取消焦点再关闭Sheet,但手动控制popover的方式更直观且兼容性更好。
内容的提问来源于stack exchange,提问作者Jaime Bocio
相关产品推荐
相关产品推荐

