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

Mac应用隐藏/最小化恢复后View菜单‘Enter Full Screen’功能失效求助

解决macOS 12下WindowGroup应用隐藏/最小化后View菜单全屏选项消失问题

问题背景

在开发目标为macOS 12.0的SwiftUI应用中(因系统版本限制,只能使用WindowGroup而无法使用macOS 13+支持的Window),执行隐藏(Cmd+H)或最小化(Cmd+M)操作后重新激活应用,出现如下异常:

  • 顶部菜单栏的View菜单点击后不显示「Enter Full Screen」选项
  • 对应的快捷键Fn+F无响应
  • 但Window菜单中的全屏选项和窗口绿色全屏按钮功能完全正常

已尝试的无效方案

以下几种方法无法解决问题,或带来额外功能限制:

  1. 监听scenePhase的active状态,手动启用菜单项目并配置全屏相关选项:
.onChange(of: scenePhase) { scene in
    switch scene {
    case .active :
        NSApplication.shared.mainMenu?.autoenablesItems = true
        NSApplication.shared.windows.forEach{ window in
            window.menu?.autoenablesItems = true
            window.menu?.items.forEach {
                if $0.title == "View" {
                    $0.submenu?.items.forEach{ item in
                        item.isEnabled = true
                        item.isHidden = false
                    }
                }
            }
        }
        NSApplication.shared.presentationOptions.insert(.fullScreen)
        NSApplication.shared.mainMenu?.setAccessibilityFullScreenButton(true)
    default:
        break
    }
}
  1. 手动为View子菜单添加「Enter Full Screen」菜单项:
// 追加方式
NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.addItem(NSMenuItem(title: "Enter Full Screen", action: #selector(NSWindow.toggleFullScreen(_:)), keyEquivalent: "F"))
// 替换方式
NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.items = [NSMenuItem(title: "Enter Full Screen", action: #selector(NSWindow.toggleFullScreen(_:)), keyEquivalent: "F")]
  1. 在ContentView的onAppear中禁用菜单自动启用:
ContentView()
    .onAppear{
        NSApplication.shared.mainMenu?.autoenablesItems = false
    }

注:方案3会导致隐藏/最小化功能受限,不符合需求

可行解决方案

方法1:显式通过CommandGroup定义View菜单全屏选项

利用SwiftUI的CommandGroup,在WindowGroup的.commands修饰符中显式声明全屏命令,替代系统默认项目,确保应用状态切换后菜单不会丢失:

WindowGroup("title", id: "id") { 
    ContentView().handlesExternalEvents(preferring: ["*"], allowing: ["*"])
}
.commands {
    // 保留原有自定义命令配置
    CommandGroup(replacing: .newItem){}
    CommandGroup(replacing: .windowList){}
        .handlesExternalEvents(matching: [])
    
    // 显式添加View菜单的全屏切换命令
    CommandGroup(after: .viewZoom) {
        Button("Enter Full Screen") {
            NSApplication.shared.windows.first?.toggleFullScreen(self)
        }
        .keyboardShortcut("F", modifiers: [.function])
        .help("Enter full screen mode")
        
        Button("Exit Full Screen") {
            NSApplication.shared.windows.first?.toggleFullScreen(self)
        }
        .keyboardShortcut("F", modifiers: [.function])
        .help("Exit full screen mode")
        .hidden(!(NSApplication.shared.windows.first?.isFullScreen ?? false))
    }
}

该方法通过自定义命令绑定系统全屏操作,保证菜单在应用激活后始终可见,同时不影响隐藏/最小化功能。

方法2:通过AppDelegate监听激活事件修复菜单

若方法1无法满足需求,可通过实现NSApplicationDelegate监听应用激活事件,手动刷新View菜单的全屏项目:

  1. 创建AppDelegate类:
class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidBecomeActive(_ notification: Notification) {
        guard let mainMenu = NSApplication.shared.mainMenu else { return }
        // 定位到View菜单
        guard let viewMenu = mainMenu.items.first(where: { $0.title == "View" })?.submenu else { return }
        
        // 移除已存在的全屏相关项,避免重复添加
        viewMenu.items.removeAll { $0.action == #selector(NSWindow.toggleFullScreen(_:)) }
        
        // 添加系统标准的全屏菜单项
        let fullScreenItem = NSMenuItem(
            title: "Enter Full Screen",
            action: #selector(NSWindow.toggleFullScreen(_:)),
            keyEquivalent: "F"
        )
        fullScreenItem.keyEquivalentModifierMask = .function
        viewMenu.insertItem(fullScreenItem, at: viewMenu.items.count)
    }
}
  1. 在App结构体中注册Delegate:
@main
struct YourApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup("title", id: "id") { 
            ContentView().handlesExternalEvents(preferring: ["*"], allowing: ["*"])
        }
        .commands {
            CommandGroup(replacing: .newItem){}
            CommandGroup(replacing: .windowList){}
                .handlesExternalEvents(matching: [])
        }
    }
}

此方法通过应用激活时强制重置View菜单的全屏项目,确保每次激活后菜单状态正常。

内容的提问来源于stack exchange,提问作者I have a question

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:00:12