You need to enable JavaScript to run this app. 如何在SwiftUI中实现场景专属状态并适配commands快捷键绑定
优惠活动
大模型
产品
解决方案
定价
更多

如何在SwiftUI中实现场景专属状态并适配commands快捷键绑定

可以通过SwiftUI提供的*焦点值(FocusedValue)*机制实现,这是官方推荐的跨焦点场景与全局命令通信的方案,具体实现步骤如下:

实现步骤

1. 定义全局焦点键

首先创建自定义的FocusedValueKey,用来作为传递当前活跃窗口状态的标识:

import SwiftUI

// 自定义焦点键,类型对应你的状态控制器
struct CompilerFocusedKey: FocusedValueKey {
    typealias Value = UIStateController
}

extension FocusedValues {
    var currentCompiler: UIStateController? {
        get { self[CompilerFocusedKey.self] }
        set { self[CompilerFocusedKey.self] = newValue }
    }
}

2. 给每个窗口绑定专属状态到焦点值

修改你的DocumentGroup实现,在初始化每个窗口的状态后,通过.focusedValue修饰符关联到前面定义的全局键:

@main
struct QCCApp: App {
    var body: some Scene {
        DocumentGroup(newDocument: QCCDocument()) { file in
            let compiler = UIStateController(targetting: file)
            ContentView()
                .environmentObject(compiler)
                // 把当前窗口的专属状态绑定到焦点键
                .focusedValue(\.currentCompiler, compiler)
        }
        .commands {
            CommandDelegate()
        }

        Settings {
            SettingsView()
        }
    }
}

3. 在全局命令中读取当前活跃窗口的状态

修改CommandDelegate的实现,通过@FocusedValue属性包装器读取当前焦点窗口对应的状态:

struct CommandDelegate: Commands {
    // 自动读取当前活跃窗口绑定的状态,无活跃窗口时为nil
    @FocusedValue(\.currentCompiler) var activeCompiler
    
    var body: some Commands {
        CommandMenu("自定义操作") {
            Button("运行编译") {
                // 只会触发当前活跃窗口的状态方法,不会影响其他窗口
                activeCompiler?.runCompile()
            }
            .keyboardShortcut("r", modifiers: .command)
            // 无活跃窗口时自动禁用快捷键
            .disabled(activeCompiler == nil)
        }
    }
}

实现原理

FocusedValue是SwiftUI专为焦点场景设计的状态传递机制:

  • 每个窗口独立绑定自己的状态到焦点键,互不干扰
  • 全局命令中读取的@FocusedValue永远是当前获得焦点(处于最前方活跃状态)的窗口对应的值
  • 无活跃窗口时属性自动为nil,可直接用来禁用不适用的快捷键

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 04:54:03