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

macOS SwiftUI列表右键菜单首次触发未正确识别目标项问题

问题分析与解决方案

这个Bug的核心原因是:macOS下首次触发ContextMenu时,actionTarget = value与isDeleting = true的状态更新存在时序问题——Sheet在actionTarget尚未完成赋值时就已经加载,导致首次显示初始的空字符串。后续操作时状态更新的时序趋于稳定,因此显示正常。

最可靠的修复方式是改用sheet(item:)绑定,而非isPresented:,因为item绑定会确保只有当目标对象被正确赋值后,Sheet才会被呈现。

修正后的代码

import SwiftUI

struct ContentView: View {
    // 将actionTarget改为可选类型,初始值为nil
    @State private var actionTarget: Value?
    // 移除isDeleting状态,改用actionTarget的nil状态控制Sheet显示
    @State private var selection = Value(name: "")
    
    struct Value: Identifiable, Hashable {
        let id = UUID()
        var name: String
    }
    let values = [Value(name: "One"), Value(name: "Two"), Value(name: "Three")]

    var body: some View {
        List(values, selection: $selection) { value in
            Text(value.name)
                .tag(value)
                .contextMenu {
                    Button {
                        // 直接赋值actionTarget,Sheet会自动触发
                        actionTarget = value
                    } label: { Text("Delete \(value.name)") }
                }
        }
        // 使用sheet(item:)绑定,绑定到actionTarget
        .sheet(item: $actionTarget) { target in
            Text("Ok to delete \"\(target.name)?\"")
                .frame(width: 300)
                .padding()
                .toolbar {
                    ToolbarItem(placement: .cancellationAction) {
                        Button("Cancel") {
                            actionTarget = nil
                        }
                    }
                    ToolbarItem(placement: .destructiveAction) {
                        Button {
                            // 执行删除逻辑
                            if let index = values.firstIndex(of: target) {
                                // 注意:values是let常量,实际项目中应改为@State数组
                                // 示例中仅演示流程
                                print("Deleted \(target.name)")
                            }
                            actionTarget = nil
                        } label: { Text("Delete") }
                    }
                }
        }
    }
}

关键改动说明

  • 将actionTarget改为可选类型Value?,初始值设为nil,通过其是否为nil来控制Sheet的显示/隐藏,替代原有的isDeleting状态变量。
  • 使用sheet(item:)替代sheet(isPresented:),该绑定方式会自动监听actionTarget的变化,只有当它被赋值为有效对象时才会呈现Sheet,从根源上避免了状态更新的时序问题。
  • Sheet内部直接使用传入的target参数(即actionTarget的当前值),无需依赖外部状态,确保显示内容准确。

另外,注意示例中values是let常量,实际项目中如果需要执行删除操作,应将其改为@State var values,以便修改数组内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:40:32