SwiftUI macOS 命令(菜单栏)和 View

标签 swift macos swiftui menubar

嗨,我开始学习 SwiftUI 和 macOS 开发。我正在使用 SwiftUI 生命周期。如何从菜单栏中的聚焦窗口调用函数。
除了 Apple 文档,我还发现了 this reference并且能够使用命令创建菜单项,但我不知道如何从我的 View 中调用函数。
例如:
假设这是我的 App 结构:

import SwiftUI

@main
struct ExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }.commands {
        CommandMenu("First menu") {
            Button("Action!") {
                // How do I call the views action function?
            }
        }
    }
}
这是我的观点:
struct ContentView: View {
    public func action() {
        print("It works")
    }
    var body: some View {
        Text("Example")
    }
}
如果有任何拼写错误,我只是输入了示例代码,但我希望您能理解。

最佳答案

因为 View SwiftUI 中的 s 是 transient 的,您不能持有对 ContentView 的特定实例的引用。调用一个函数。但是,您可以做的是更改传递给内容 View 的状态的一部分。
例如:

@main
struct ExampleApp: App {
    @StateObject var appState = AppState()
    
    var body: some Scene {
        WindowGroup {
            ContentView(appState: appState)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }.commands {
            CommandMenu("First menu") {
                Button("Action!") {
                    appState.textToDisplay = "\(Date())"
                }
            }
        }
    }
}

class AppState : ObservableObject {
    @Published var textToDisplay = "(not clicked yet)"
}

struct ContentView: View {
    @ObservedObject var appState : AppState
    
    var body: some View {
        Text(appState.textToDisplay)
    }
}

请注意 .commands修饰符继续 WindowGroup { }在本例中,AppStateObservableObject保存应用程序的某些状态。它已通过 ContentView使用参数。您也可以通过环境对象( https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views )传递它
当菜单项被点击时,它设置 textToDisplay这是一个 @Published属性(property)在 AppState . ContentView将随时更新 AppState 的 @Published 属性得到更新。
这是您将使用的模式的总体思路。如果您有此模式未涵盖的用例,请在评论中告诉我。
更新,基于您的评论 :
import SwiftUI
import Combine

@main
struct ExampleApp: App {
    @StateObject var appState = AppState()
    
    var body: some Scene {
        WindowGroup {
            ContentView(appState: appState)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }.commands {
            CommandMenu("First menu") {
                Button("Action!") {
                    appState.textToDisplay = "\(Date())"
                }
                Button("Change background color") {
                    appState.contentBackgroundColor = Color.green
                }
                Button("Toggle view") {
                    appState.viewShown.toggle()
                }
                Button("CustomCopy") {
                    appState.customCopy.send()
                }
            }
        }
    }
}

class AppState : ObservableObject {
    @Published var textToDisplay = "(not clicked yet)"
    @Published var contentBackgroundColor = Color.clear
    @Published var viewShown = true
    
    var customCopy = PassthroughSubject<Void,Never>()
}

class ViewModel : ObservableObject {
    @Published var text = "The text I have here"
    var cancellable : AnyCancellable?

    func connect(withAppState appState: AppState) {
        cancellable = appState.customCopy.sink(receiveValue: { _ in
            print("Do custom copy based on my state: \(self.text) or call a function")
        })
    }
}

struct ContentView: View {
    @ObservedObject var appState : AppState
    @State var text = "The text I have here"
    @StateObject private var viewModel = ViewModel()
    
    var body: some View {
        VStack {
            Text(appState.textToDisplay)
                .background(appState.contentBackgroundColor)
            if appState.viewShown {
                Text("Shown?")
            }
        }
        .onReceive(appState.$textToDisplay) { (newText) in
            print("Got new text: \(newText)")
        }
        .onAppear {
            viewModel.connect(withAppState: appState)
        }
    }
}
在我的更新中,您可以看到我已经解决了背景颜色的问题,显示隐藏 View ,甚至在 @Published 属性之一更改时收到通知(通过 onReceive )。
您还可以看到我如何使用自定义发布者 ( customCopy ) 将操作传递给 ContentViewViewModel

关于SwiftUI macOS 命令(菜单栏)和 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66557093/

相关文章:

Swift Playground 1 级 gem 农场 - 功能代码不起作用

Swift 协议(protocol)错误 : 'weak' cannot be applied to non-class type

Swift 单元测试错误 : symbol(s) not found for architecture x86_64 (Swift Package Manager)

macos - 使用 hammerspoon 和 spaces 模块将窗口移动到新空间

swift - Swiftui 中 init() 中的变量前的下划线是什么意思?

ios - 在 SwiftUI 中使用动态表单和字段状态

ios - 在 Assets 库中播放音频

objective-c - SecTrustEvaluate 没有按预期失败?

ios - 在加载时将 @State 变量从 UserDefaults 更改为值而不更新 Picker

c - 如何正确设置sigaltstack?