SwiftUI如何为每个场景单独创建变量 解决iPadOS 15 Commands全局生效问题
实现方案
你可以通过 @FocusedValue 结合场景内独立状态持有实现单场景专属Commands,具体步骤如下:
- 先定义全局的FocusedValue键,用于传递当前场景的Commands实例
import SwiftUI class GlobalCommands: ObservableObject { // 你的Commands相关状态和逻辑 @Published var someButtonTitle = "场景专属操作" @Published var isActionEnabled = false var commands: some Commands { CommandMenu("自定义菜单") { Button(someButtonTitle) { // 执行对应操作 isActionEnabled.toggle() } .disabled(!isActionEnabled) } } } // 定义FocusedKey用于传递场景级Commands实例 struct SceneCommandsKey: FocusedValueKey { typealias Value = GlobalCommands } extension FocusedValues { var sceneCommands: GlobalCommands? { get { self[SceneCommandsKey.self] } set { self[SceneCommandsKey.self] = newValue } } }
- 将GlobalCommands实例下放到每个场景的根视图内部持有,使用
@StateObject保证每个场景独立生成实例,同时注入到当前场景的FocusedValues中
struct ContentView: View { // 每个场景的ContentView都会生成独立的GlobalCommands实例 @StateObject private var sceneCommands = GlobalCommands() var body: some View { // 你的原有视图内容 VStack { Text("当前场景操作状态:\(sceneCommands.isActionEnabled ? "开启" : "关闭")") } // 将当前场景的Commands实例注入到FocusedValues中 .focusedValue(\.sceneCommands, sceneCommands) } }
- App层级的Commands配置直接读取当前聚焦场景的实例即可,不需要全局持有
@main struct I_FeelApp: App { var body: some Scene { WindowGroup { ContentView() } .commands { // 读取当前聚焦场景的Commands实例 @FocusedValue(\.sceneCommands) var currentCommands if let currentCommands = currentCommands { currentCommands.commands } } } }
方案说明
- 每个场景的根视图会独立生成
GlobalCommands实例,修改不会同步到其他场景 - 系统的Commands默认绑定当前聚焦的场景,通过
@FocusedValue读取的永远是当前活跃场景的专属实例 - 完全符合SwiftUI官方状态管理规则,不需要手动管理场景生命周期
内容的提问来源于stack exchange,提问作者Zapata
相关产品推荐
相关产品推荐

