You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。具体实现步骤如下:

  1. 给Detail视图添加状态变量,控制ColorPicker的popover显示/隐藏
  2. 将原生ColorPicker改为通过Button触发自定义popover的形式
  3. 在「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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:50:23