実現しようとしたこと
- 端末の中に保存されているファイルのアップロードを実現しようとした
- 下から画面がにゅっと出てきて端末の中に保存されているファイル一覧が表示される処理を実現しようとした
方針
- どうやら
UIDocumentPickerViewControllerなるものを使うことでそれが実現できるらしい -
SwiftUIにはそれを実現できる方法がないのでUIKitのUIDocumentPickerViewControllerというコントローラーをViewControllerRepresentableを用いてラップすることで、むりくり実現が出来る。
解決策
DocumentPickerクラスの準備
- 事前準備として、
DocumentPickerというクラスを準備しておく。
DocumentPicker.swift
import SwiftUI
import UIKit
import UniformTypeIdentifiers
struct DocumentPicker: UIViewControllerRepresentable {
var onPick: (URL) -> Void
func makeUIViewController(context: Context) -> some UIViewController {
let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.item], asCopy: true)
picker.delegate = context.coordinator
picker.allowsMultipleSelection = false
return picker
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(onPick: onPick)
}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var onPick: (URL) -> Void
init(onPick: @escaping (URL) -> Void) {
self.onPick = onPick
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
onPick(urls.first!)
}
}
}
-
makeUIViewControllerでは端末からDocument一覧画面を開き、delegateにCoordinatorを指定する。 -
Coorindatorの中ではアイテムがPickされた時のアイテムの登録処理の指定を行う -
Coordinatorがdelegateを橋渡しして画面にURLを返す
というのが大体の流れになります
Viewから呼び出す
ContentView.swift
@State private var selectedFileURL: URL?
// 省略
.sheet(isPresented: $showPicker) {
DocumentPicker { url in
selectedFileURL = url
// do something
}
}
- あとはViewからurlを取得することができるので任意の操作を行うという流れになります。
-
UIViewRepresentableだとmakeUIViewupdateUIViewとなるのに、それのController版だとmakeUIViewControllerupdateUIViewControllerになるのがかわいいなと思いました