在 SwiftUI 中将值从 App 传递到 ContentView
Passing a Value from App to ContentView in SwiftUI
我找到了很多关于如何让用户 select 一个菜单项然后打开一个文件夹的资源。以下是我的。
import SwiftUI
@main
struct Oh_My_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.frame(width: 480.0, height: 320.0)
}.commands {
CommandGroup(after: .newItem) {
Button {
if let url = showFileOpenPanel() {
print(url.path)
}
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
好的。那没问题。我可以打印文件路径。那么,我的实际问题是如何将此值 return 变为 ContentView
? ContentView
实际上是此示例应用程序中的显示 运行。所以我使用 ObservableObject
如下。
import SwiftUI
@main
struct Oh_My_App: App {
@StateObject var menuObservable = MenuObservable()
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
CommandGroup(after: .newItem) {
Button {
menuObservable.openFile()
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
}
class MenuObservable: ObservableObject {
@Published var fileURL: URL = URL(fileURLWithPath: "")
func openFile() {
if let openURL = showFileOpenPanel() {
fileURL = openURL
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
// ContentView.swift //
import SwiftUI
struct ContentView: View {
@ObservedObject var menuObservable = MenuObservable()
@State var filePath: String = ""
var body: some View {
ZStack {
VStack {
Text("Hello: \(filePath)")
}.onChange(of: menuObservable.fileURL) { newValue in
filePath = newValue.path
}
}
}
}
我的 ContentView
不会更新。那么如何让 ContentView
从 App
的菜单调用中接收值?谢谢。
现在,您正在 ContentView
中创建 MenuObservable
的 新实例 ,因此它与收到菜单命令。您需要传递对现有实例的引用(即 Oh_My_App
拥有的实例)。
在您的 ContentView
中,将 @ObservedObject var menuObservable = MenuObservable()
更改为:
@ObservedObject var menuObservable : MenuObservable
在你的 Oh_My_App
中:
WindowGroup {
ContentView(menuObservable: menuObservable)
}
我找到了很多关于如何让用户 select 一个菜单项然后打开一个文件夹的资源。以下是我的。
import SwiftUI
@main
struct Oh_My_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.frame(width: 480.0, height: 320.0)
}.commands {
CommandGroup(after: .newItem) {
Button {
if let url = showFileOpenPanel() {
print(url.path)
}
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
好的。那没问题。我可以打印文件路径。那么,我的实际问题是如何将此值 return 变为 ContentView
? ContentView
实际上是此示例应用程序中的显示 运行。所以我使用 ObservableObject
如下。
import SwiftUI
@main
struct Oh_My_App: App {
@StateObject var menuObservable = MenuObservable()
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
CommandGroup(after: .newItem) {
Button {
menuObservable.openFile()
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
}
class MenuObservable: ObservableObject {
@Published var fileURL: URL = URL(fileURLWithPath: "")
func openFile() {
if let openURL = showFileOpenPanel() {
fileURL = openURL
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
// ContentView.swift //
import SwiftUI
struct ContentView: View {
@ObservedObject var menuObservable = MenuObservable()
@State var filePath: String = ""
var body: some View {
ZStack {
VStack {
Text("Hello: \(filePath)")
}.onChange(of: menuObservable.fileURL) { newValue in
filePath = newValue.path
}
}
}
}
我的 ContentView
不会更新。那么如何让 ContentView
从 App
的菜单调用中接收值?谢谢。
现在,您正在 ContentView
中创建 MenuObservable
的 新实例 ,因此它与收到菜单命令。您需要传递对现有实例的引用(即 Oh_My_App
拥有的实例)。
在您的 ContentView
中,将 @ObservedObject var menuObservable = MenuObservable()
更改为:
@ObservedObject var menuObservable : MenuObservable
在你的 Oh_My_App
中:
WindowGroup {
ContentView(menuObservable: menuObservable)
}