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

SwiftUI iPad端.sheet/.fullScreenCover初次关闭失败后无法再关闭

解决iPad上SwiftUI Sheet含ColorPicker时关闭按钮失效问题

在iPad的SwiftUI应用中,当Sheet内包含ColorPicker和工具栏关闭按钮时,会出现以下异常:

  • 当ColorPicker的调色板处于显示状态时,若误触背景中的关闭按钮,Sheet不会关闭,且后续点击关闭按钮也无法生效,只能通过点击Sheet外部区域关闭(若使用.fullScreenCover则彻底无法关闭)。
  • 该问题仅出现在iPad上,iPhone上第二次点击关闭按钮即可正常关闭Sheet。

问题根源是ColorPicker激活状态下调用dismiss()或设置绑定的isPresenting为false时,Sheet的关闭流程被中断,导致状态异常,后续关闭操作失效。


方案一:延迟执行Sheet关闭操作

通过延迟设置Sheet的绑定状态,确保ColorPicker的调色板先完成关闭,再处理Sheet的关闭。这种方式无需自定义组件,实现简单:

import SwiftUI

struct SomePickerView: View {
    @State var colourBackground: Color = .clear
    @Binding var isPresented: Bool

    var body: some View {
        ColorPicker("", selection: $colourBackground)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Dismiss") {
                        // 延迟0.1秒执行关闭,给ColorPicker弹窗足够的关闭时间
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                            isPresented = false
                        }
                    }
                }
            }
    }
}

struct SomeParentView: View {
    @State var showSomePickerView: Bool = false

    var body: some View {
        Button("Pick a colour") {
            showSomePickerView = true
        }
        .sheet(isPresented: $showSomePickerView) {
            NavigationStack {
                SomePickerView(isPresented: $showSomePickerView)
            }
        }
    }
}

方案二:自定义ColorPicker并禁用激活状态下的关闭按钮

通过封装UIKit的UIColorPickerViewController,获取调色板的激活状态,在激活时禁用关闭按钮,从根源避免误触:

1. 封装自定义ColorPicker

import SwiftUI
import UIKit

struct CustomColorPicker: UIViewControllerRepresentable {
    @Binding var selection: Color
    @Binding var isPickerActive: Bool

    func makeUIViewController(context: Context) -> UIColorPickerViewController {
        let picker = UIColorPickerViewController()
        picker.delegate = context.coordinator
        picker.selectedColor = UIColor(selection)
        return picker
    }

    func updateUIViewController(_ uiViewController: UIColorPickerViewController, context: Context) {
        uiViewController.selectedColor = UIColor(selection)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UIColorPickerViewControllerDelegate {
        let parent: CustomColorPicker

        init(_ parent: CustomColorPicker) {
            self.parent = parent
        }

        func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
            parent.selection = Color(viewController.selectedColor)
        }

        func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) {
            parent.isPickerActive = false
        }

        func colorPickerViewControllerWillPresent(_ viewController: UIColorPickerViewController) {
            parent.isPickerActive = true
        }
    }
}

2. 在视图中使用自定义Picker并禁用按钮

struct SomePickerView: View {
    @State var colourBackground: Color = .clear
    @Binding var isPresented: Bool
    @State private var isColorPickerActive = false

    var body: some View {
        CustomColorPicker(selection: $colourBackground, isPickerActive: $isColorPickerActive)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Dismiss") {
                        isPresented = false
                    }
                    .disabled(isColorPickerActive) // 调色板激活时禁用关闭按钮
                }
            }
    }
}

struct SomeParentView: View {
    @State var showSomePickerView: Bool = false

    var body: some View {
        Button("Pick a colour") {
            showSomePickerView = true
        }
        .sheet(isPresented: $showSomePickerView) {
            NavigationStack {
                SomePickerView(isPresented: $showSomePickerView)
            }
        }
    }
}

方案对比

  • 方案一:实现成本低,仅需添加延迟逻辑,但属于临时 workaround,依赖时间延迟的稳定性。
  • 方案二:从根源解决问题,通过状态控制避免误操作,但需要封装UIKit组件,代码量稍大。

内容的提问来源于stack exchange,提问作者djmlewis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:07:52