如何打开文件对话框?

问题描述 投票:0回答:2

在 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) {
  }
}

这是正确的做法吗?
怎么了?

swift macos swiftui
2个回答
62
投票

实际上你不需要,因为

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)
  }
}

0
投票

我建议使用原生 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()
等功能来安全访问文件内容

© www.soinside.com 2019 - 2024. All rights reserved.