在 macOS 上的 SwiftUI 应用程序中,我希望允许用户从 macOS 文件系统中选择文件。
我尝试使用AppKit的
NSOpenPanel
。
我尝试了这样的操作,但无法创建
NSViewControllerRepresentable
。
struct ContentView: View {
@State var filename = "Filename"
@State var showFileChooser = false
var body: some View {
HStack {
Text(filename)
Button("select File")
{ self.showFileChooser = true
}.sheet(isPresented: $showFileChooser)
{ FileChooser()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct FileChooser : {
func makeNSViewController(context: Context) -> NSOpenPanel {
NSOpenPanel()
}
func updateNSViewControler(_ nsView: NSOpenPanel, context: Context) {
}
}
这是正确的做法吗?
怎么了?
实际上你不需要,因为
NSOpenPanel
是一个窗口,而不是视图控制器。
这是可能的方法。使用 Xcode 11.7 / macOS 10.15.6 进行测试
struct ContentView: View {
@State var filename = "Filename"
@State var showFileChooser = false
var body: some View {
HStack {
Text(filename)
Button("select File")
{
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
if panel.runModal() == .OK {
self.filename = panel.url?.lastPathComponent ?? "<none>"
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
我建议使用原生 SwiftUI
.fileImporter
,如下所示:
.fileImporter(isPresented: $showFileImporter, allowedContentTypes: [.json]) { result in
switch result {
case .success(let url):
// Process file URL here
case .failure(let error):
// Process error here
}
}
$showFileImporter
的类型是 Binding<Bool>
所以你可能想使用 @State var showFileImporter = false
.json
之外,请检查UTType
(https://developer.apple.com/documentation/uniformtypeidentifiers/uttype)Result<URL, Error>
allowsMultipleSelection: true
以允许选择多个文件(在这种情况下,结果类型为 Result<[URL], Error>
,因此您可以迭代选定的 URL
)根据平台和沙箱设置,您可能需要为您的应用程序启用“读取文件权限”,并使用
.startAccessingSecurityScopedResource()
等功能来安全访问文件内容