如何使用催化剂在 ios 和 macOS 中弹出文档选择器
Posted
技术标签:
【中文标题】如何使用催化剂在 ios 和 macOS 中弹出文档选择器【英文标题】:How to popup a document picker in ios and macos using catalyst 【发布时间】:2020-03-05 15:46:06 【问题描述】:我正在尝试使用 mac 催化剂弹出一个文档选择器,但我得到的只是一个空白屏幕。
在 iPad 和 iPhone 上的 ios 13.2.2 上一切正常,但在 macos 10.15.1 catalina 上却不行。
有谁知道如何使用催化剂在 ios 和 macos 中弹出文档选择器?
我的权利文件有:
<key>com.apple.security.app-sandbox</key>
<false/>
这是显示问题的测试代码。
import Foundation
import SwiftUI
struct ContentView: View
@State var isFilePickerShown = false
var body: some View
VStack
Button(action: self.isFilePickerShown.toggle() )
Image(systemName: "rectangle.and.paperclip").resizable().frame(width: 70, height: 70)
.sheet(isPresented: $isFilePickerShown, onDismiss: self.isFilePickerShown = false)
DocPickerViewController(callback: self.filePicked, onDismiss: self.isFilePickerShown = false )
func filePicked(_ url: URL)
print("\nThe url is: \(url)")
struct DocPickerViewController: UIViewControllerRepresentable
private let docTypes: [String] = ["com.adobe.pdf", "public.text", "public.composite-content"]
var callback: (URL) -> ()
private let onDismiss: () -> Void
init(callback: @escaping (URL) -> (), onDismiss: @escaping () -> Void)
self.callback = callback
self.onDismiss = onDismiss
func makeCoordinator() -> Coordinator Coordinator(self)
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocPickerViewController>)
func makeUIViewController(context: Context) -> UIDocumentPickerViewController
let controller = UIDocumentPickerViewController(documentTypes: docTypes, in: .import)
controller.allowsMultipleSelection = false
controller.delegate = context.coordinator
return controller
class Coordinator: NSObject, UIDocumentPickerDelegate
var parent: DocPickerViewController
init(_ pickerController: DocPickerViewController)
self.parent = pickerController
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL])
parent.callback(urls[0])
parent.onDismiss()
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController)
parent.onDismiss()
我得到了下面的代码。但实际上这是 一个混乱的业务,我觉得这不是答案。
现在我在尝试显示时遇到了同样的问题 一个 UIActivityViewController。我可以使用相同的方法在 Mac 上显示它,但是 我无法控制它出现在哪里。它总是在 (0,0)。
struct FilePicker: UIViewControllerRepresentable
private let docTypes: [String] = ["com.adobe.pdf", "public.text", "public.composite-content"]
private let controller: FilePickerController?
var callback: (URL) -> ()
private let onDismiss: () -> Void
init(callback: @escaping (URL) -> (), onDismiss: @escaping () -> Void)
self.callback = callback
self.onDismiss = onDismiss
self.controller = FilePickerController(documentTypes: docTypes, mode: .import)
func makeCoordinator() -> Coordinator
return Coordinator(self)
func updateUIViewController(_ uiViewController: FilePickerController, context: UIViewControllerRepresentableContext<FilePicker>)
func makeUIViewController(context: Context) -> FilePickerController
return controller!
class Coordinator: NSObject, FilePickerControllerDelegate
var parent: FilePicker
init(_ filePicker: FilePicker)
self.parent = filePicker
super.init()
self.parent.controller?.delegate = self
func documentPicker(_ controller: FilePickerController, didPickDocumentsAt urls: [URL])
parent.callback(urls[0])
parent.onDismiss()
func documentPickerWasCancelled(_ controller: FilePickerController)
parent.onDismiss()
protocol FilePickerControllerDelegate: class
func documentPickerWasCancelled(_ controller: FilePickerController)
func documentPicker(_ controller: FilePickerController,
didPickDocumentsAt urls: [URL])
class FilePickerController: UIViewController, UIDocumentPickerDelegate
weak var delegate: FilePickerControllerDelegate?
let viewController: UIDocumentPickerViewController?
public init(documentTypes: [String], mode: UIDocumentPickerMode)
viewController = UIDocumentPickerViewController(documentTypes: documentTypes, in: mode)
super.init(nibName: nil, bundle: nil)
required public init?(coder: NSCoder)
viewController = UIDocumentPickerViewController(coder: coder)
super.init(coder: coder)
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
if let viewController = viewController
viewController.delegate = self
self.present(viewController, animated: animated)
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL])
self.dismiss(animated: false)
self.delegate?.documentPicker(self, didPickDocumentsAt: urls)
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController)
self.dismiss(animated: false)
self.delegate?.documentPickerWasCancelled(self)
我这样称呼它:
.sheet(isPresented: $isShown, onDismiss: self.isShown = false)
#if targetEnvironment(macCatalyst)
FilePicker(callback: self.filePicked, onDismiss: self.isShown = false )
#else
DocPickerViewController(callback: self.filePicked, onDismiss: self.isShown = false )
#endif
【问题讨论】:
你搞清楚了吗? 【参考方案1】:解决方法:为催化剂提供选择器控制器
UIApplication.shared.firstKeyWindow?.rootViewController!.present(self.picker.controller!, animated: true)
extension UIApplication
public var firstKeyWindow: UIWindow?
windows.first(where: $0.isKeyWindow )
【讨论】:
【参考方案2】:所有代码来自hstdt
和workingdog
。
import SwiftUI
struct ContentView: View
@State private var isFilePickerShown = false
@State private var picker = DocumentPicker()
var body: some View
VStack
Button(action:
self.isFilePickerShown.toggle()
#if targetEnvironment(macCatalyst)
UIApplication.shared.windows[0].rootViewController!.present(self.picker.viewController, animated: true)
#endif
)
Image(systemName: "rectangle.and.paperclip").resizable().frame(width: 70, height: 70)
.sheet(isPresented: $isFilePickerShown, onDismiss: self.isFilePickerShown = false)
DocPickerViewController(callback: self.filePicked, onDismiss: self.isFilePickerShown = false )
func filePicked(_ url: URL)
print("\nThe url is: \(url)")
现在为 MacOS 创建新的 swiftui 文件 DocumentPicker
:
import SwiftUI
final class DocumentPicker: NSObject, UIViewControllerRepresentable
typealias UIViewControllerType = UIDocumentPickerViewController
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])
print(urls)
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController)
controller.dismiss(animated: true)
print("cancelled")
此代码使用催化剂在 iOS 和 MacOS 中弹出一个文档选择器。
使用 MacOS Catalyst 使用 DocumentPicker
类,使用 iOS 使用 DocPickerViewController
workingdog
编写(参见上面的workingdog
帖子)
【讨论】:
【参考方案3】:这是 Cesare Piersigilli 在 GitHub 上的示例:https://github.com/AndreasPrang/Catalyst-File-Picker
【讨论】:
以上是关于如何使用催化剂在 ios 和 macOS 中弹出文档选择器的主要内容,如果未能解决你的问题,请参考以下文章
为 mac 催化剂的 info.plist 文件中的键设置不同的值