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

MacOS应用SwiftUI ContentView点击需多次触发的解决求助

问题

开发MacOS Swift应用时,通过SwiftUI的ContentView实现状态栏菜单(MenuItem),ContentView能正常显示,但其中Text绑定的点击手势需要3-4次才能触发,怀疑是窗口层级问题导致点击事件无法正常传递。

相关代码如下:

StatusBarController 代码

class StatusBarController {
    
    var statusBar: NSStatusBar!
    var statusItem: NSStatusItem!
    var nsMenu = NSMenu()
    
    init(delegate: AppDelegate) {
        
        statusBar = NSStatusBar()
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

        statusItem.button?.image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Status bar icon")

        let menuItem = NSMenuItem()
        let controller = NSHostingController(rootView: ContentView())
        
        controller.view.frame.size = CGSize(width: 250, height: 320)
        menuItem.view = controller.view
        
        
        nsMenu.addItem(menuItem)
        statusItem.menu = nsMenu
    }
}

ContentView 代码

struct ContentView: View {

    var body: some View {

        VStack(alignment: .leading, spacing: 0) {
            
            
            HStack() {
                Text("Quit")
                        .font(.title3)
                        .fontWeight(.medium)
                        .foregroundColor(.black)
                        .padding(.leading, 10)
                        .padding(.top, 10)
                Spacer()
            }
            .contentShape(Rectangle()).onTapGesture {
                
                // 此处为需触发的点击动作
                NSApp.terminate(self)
            }
        }
    }
}
解决方案

问题根源是NSMenuItem中的SwiftUI视图未获得正确的事件响应优先级,通过以下修改可让点击一次即生效:

  1. 禁用NSMenuItem默认事件拦截
    将menuItem的isEnabled设为false,避免它抢占SwiftUI视图的点击事件。
  2. 让SwiftUI视图成为第一响应者
    调用controller.view.becomeFirstResponder(),确保事件优先传递到SwiftUI视图。

修改后的StatusBarController代码:

class StatusBarController {
    
    var statusBar: NSStatusBar!
    var statusItem: NSStatusItem!
    var nsMenu = NSMenu()
    
    init(delegate: AppDelegate) {
        
        statusBar = NSStatusBar()
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

        statusItem.button?.image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Status bar icon")

        let menuItem = NSMenuItem()
        let controller = NSHostingController(rootView: ContentView())
        
        controller.view.frame.size = CGSize(width: 250, height: 320)
        // 禁用MenuItem默认事件处理,避免拦截点击
        menuItem.isEnabled = false
        // 让SwiftUI视图成为第一响应者,优先接收事件
        controller.view.becomeFirstResponder()
        
        menuItem.view = controller.view
        
        nsMenu.addItem(menuItem)
        statusItem.menu = nsMenu
    }
}

额外优化:可扩大ContentView的点击响应范围,确保整个区域都能触发动作,修改后的ContentView代码:

struct ContentView: View {

    var body: some View {

        VStack(alignment: .leading, spacing: 0) {
            HStack() {
                Text("Quit")
                        .font(.title3)
                        .fontWeight(.medium)
                        .foregroundColor(.black)
                        .padding(.leading, 10)
                        .padding(.top, 10)
                Spacer()
            }
        }
        .contentShape(Rectangle())
        .onTapGesture {
            NSApp.terminate(self)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:15:25