Swiftui UIDocumentPickerViewController不';不要在Mac Catalyst上显示任何内容
UIDocumentPickerViewController可以在iOS上工作,但不能在Mac Catalyst上工作。是否有其他解决此问题的方法?顺便说一句,Mac Catalyst上的NSOpenPanel不可用Swiftui UIDocumentPickerViewController不';不要在Mac Catalyst上显示任何内容,swiftui,mac-catalyst,Swiftui,Mac Catalyst,UIDocumentPickerViewController可以在iOS上工作,但不能在Mac Catalyst上工作。是否有其他解决此问题的方法?顺便说一句,Mac Catalyst上的NSOpenPanel不可用 import SwiftUI final class DocumentPicker: NSObject, UIViewControllerRepresentable, ObservableObject { typealias UIViewControlle
import SwiftUI
final class DocumentPicker: NSObject, UIViewControllerRepresentable, ObservableObject {
typealias UIViewControllerType = UIDocumentPickerViewController
@Published var urlsPicked = [URL]()
lazy var viewController:UIDocumentPickerViewController = {
// For picked only folder
let vc = UIDocumentPickerViewController(documentTypes: ["public.folder"], in: .open)
// For picked every document
// let vc = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .open)
// For picked only images
// let vc = UIDocumentPickerViewController(documentTypes: ["public.image"], in: .open)
vc.allowsMultipleSelection = false
// vc.accessibilityElements = [kFolderActionCode]
// vc.shouldShowFileExtensions = true
vc.delegate = self
return vc
}()
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
viewController.delegate = self
return viewController
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
}
extension DocumentPicker: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
urlsPicked = urls
print("DocumentPicker geoFolder.geoFolderPath: \(urlsPicked[0].path)")
}
// func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
// controller.dismiss(animated: true) {
// }
// }
}
以下示例适用于Mac Catalyst。如果要在iOS和Mac Catalyst上支持UIDocumentPickerViewController,应使用
#if targetEnvironment(macCatalyst)
//code for Mac Catalyst
#endif
如何在Mac Catalyst上支持UIDocumentPickerViewController
//SceneDelegate.swift
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var picker = DocumentPicker()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
window.rootViewController?.present(picker.viewController, animated: true)
}
}
}
//ContentView.swift
final class DocumentPicker: NSObject, UIViewControllerRepresentable {
typealias UIViewControllerType = UIDocumentPickerViewController
lazy var viewController: UIDocumentPickerViewController = {
let vc = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .open)
vc.delegate = self
return vc
}()
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
viewController.delegate = self
return viewController
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
}
extension DocumentPicker: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
print(urls)
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true, completion: nil)
print("cancelled")
}
}
//SceneDelegate.swift
导入UIKit
导入快捷键
类SceneDelegate:UIResponder,UIWindowSceneDelegate{
变量窗口:UIWindow?
var picker=DocumentPicker()
func场景(场景:UIScene,willConnectTo会话:UISceneSession,选项connectionOptions:UIScene.connectionOptions){
让contentView=contentView()
//使用UIHostingController作为窗口根视图控制器。
如果让windowScene=场景为?UIWindowScene{
let window=UIWindow(windowScene:windowScene)
window.rootViewController=UIHostingController(rootView:contentView)
self.window=window
window.makeKeyAndVisible()的
window.rootViewController?.present(picker.viewController,动画:true)
}
}
}
//ContentView.swift
最终类文档选择器:NSObject,UIViewControllerRepresentable{
typealias UIViewControllerType=UIDocumentPickerViewController
lazy var viewController:UIDocumentPickerViewController={
让vc=UIDocumentPickerViewController(文档类型:[“public.data”],位于:。打开)
vc.delegate=self
返回vc
}()
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->UIDocumentPickerViewController{
viewController.delegate=self
返回视图控制器
}
func updateUIViewController(uUIViewController:UIDocumentPickServiceWCONTROLLER,上下文:UIViewControllerRepresentableContext){
}
}
扩展文档选择器:UIDocumentPickerDelegate{
func documentPicker(uController:UIDocumentPickerViewController,didPickDocumentsAt URL:[URL]){
打印(URL)
}
取消func documentpickerwascanced(u控制器:UIDocumentPickerViewController){
控制器。解除(动画:true,完成:nil)
打印(“已取消”)
}
}
感谢Simon,没有他的帮助,我无法解决这个问题。经过多次尝试,我终于找到了下面的代码,它可以在Mac Catalyst上与Xcode 11.3.1配合使用
import SwiftUI
final class DocumentPicker: NSObject, UIViewControllerRepresentable, ObservableObject {
typealias UIViewControllerType = UIDocumentPickerViewController
@Published var urlsPicked = [URL]()
lazy var viewController:UIDocumentPickerViewController = {
// For picked only folder
let vc = UIDocumentPickerViewController(documentTypes: ["public.folder"], in: .open)
// For picked every document
// let vc = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .open)
// For picked only images
// let vc = UIDocumentPickerViewController(documentTypes: ["public.image"], in: .open)
vc.allowsMultipleSelection = false
// vc.accessibilityElements = [kFolderActionCode]
// vc.shouldShowFileExtensions = true
vc.delegate = self
return vc
}()
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
viewController.delegate = self
return viewController
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
}
extension DocumentPicker: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
urlsPicked = urls
print("DocumentPicker geoFolder.geoFolderPath: \(urlsPicked[0].path)")
}
// func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
// controller.dismiss(animated: true) {
// }
// }
}
我希望我能有所帮助。在@uncheartedworks的优秀答案中有额外的代码。这是一个更干净的版本,带有一些选项,可以在代码中进行更多的复制/粘贴。这适用于iOS、iPadOS和Mac Catalyst(无需使用#if条件) 重要提示:将“com.apple.security.files.user selected.read-write”(布尔值,设置为YES)权限添加到应用程序的权限文件中,否则当您在Mac上打开选择器时,它将崩溃。如果您只需要读取访问权限,则可以使用“com.apple.security.files.user selected.read” 示例用法:
struct ContentView: View {
/// The view controller for the sheet that lets the user select the project support folder
///
/// Yes, I said "view controller" - we need to go old school for Catalyst and present a view controller from the root view controller manually.
@State var filePicker: DocumentPicker
init() {
// Setting filePicker like this lets us keep DocumentPicker in the view
// layer (instead of a model or view model), lets SwiftUI hang onto
// the reference to it, and lets you specify another function to
// call (e.g. one from a view model) using info passed into your
// init method.
_filePicker = State(initialValue: DocumentPicker({urls in
print(urls)
}))
}
var body: some View {
Button("Pick a folder") {
self.presentDocumentPicker()
}
}
/// Presents the document picker from the root view controller
///
/// This is required on Catalyst but works on iOS and iPadOS too, so we do it this way instead of in a UIViewControllerRepresentable
func presentDocumentPicker() {
let viewController = UIApplication.shared.windows[0].rootViewController!
let controller = self.filePicker.viewController
viewController.present(controller, animated: true)
}
}
我也有这个问题。我还没有找到解决办法…你们找到解决办法了吗?这不管用。有关更多详细信息,请参阅我的问题:在iOS中工作正常,而不是在MacOs中。阅读评论,它看起来是来自卡塔琳娜。而且Swift UI在警报时也不稳定。MacOS中的contextMenu提供了“未知的可序列化元素,将其作为可访问性元素返回可能会导致崩溃”。问题是该怎么办?警报和上下文菜单可以手工制作。但在MacOS中,选择打开文件(UIDocumentPickerViewController)和保存(UIApplication)不会起作用,手工制作要困难得多?是否有一个很快从苹果升级的解决方案,有什么好的解决办法,或者我们希望制作一个手工制作的解决方案?有什么提示吗?而且我认为很遗憾我们没有catalyst文件选择器和文档保存器/发送器(没有它是致命的)。Catalyst Mac程序(风格类似iOS的Mac程序)实际上看起来非常好。Catalyst的SwiftUI要比仅Mac的SwiftUI更容易看起来好看。此外,Mac用户一般都是iOS用户,很少有例外,他们不仅接受而且会欣赏Mac程序的发展,更希望Mac程序发展成轻微的iOS风格,这意味着它具有商业价值。如果我们只需要选取器和保存器/发送器,那么Catalyst是一个非常好的开发。这是值得努力的。是的,你必须使用Catalina。我同意你的看法,苹果应该支持此功能。请注意,你需要将“com.Apple.security.files.user selected.read-write”(布尔值,设置为“是”)权限添加到你的应用程序的权限文件中,否则当你打开选择器时它会崩溃(例如,如果你将此代码复制/粘贴到新的Xcode项目并运行它)。
struct ContentView: View {
/// The view controller for the sheet that lets the user select the project support folder
///
/// Yes, I said "view controller" - we need to go old school for Catalyst and present a view controller from the root view controller manually.
@State var filePicker: DocumentPicker
init() {
// Setting filePicker like this lets us keep DocumentPicker in the view
// layer (instead of a model or view model), lets SwiftUI hang onto
// the reference to it, and lets you specify another function to
// call (e.g. one from a view model) using info passed into your
// init method.
_filePicker = State(initialValue: DocumentPicker({urls in
print(urls)
}))
}
var body: some View {
Button("Pick a folder") {
self.presentDocumentPicker()
}
}
/// Presents the document picker from the root view controller
///
/// This is required on Catalyst but works on iOS and iPadOS too, so we do it this way instead of in a UIViewControllerRepresentable
func presentDocumentPicker() {
let viewController = UIApplication.shared.windows[0].rootViewController!
let controller = self.filePicker.viewController
viewController.present(controller, animated: true)
}
}