SwiftUIにはUIImagePickerがない!
悲しいかなまだまだ発展途上のSwiftUIなのでImagePickerはありません。
なのでuiKitのUIImagePickerをSwiftUiで使う方法を解説します。
uiKitのImagePickerをSwiftUI側で使う方法

UIViewControllerRepresentableにImagePickerをセット
- SwiftUIと繋がるBindingオブジェクトとしてImagePickerで取得出来るUIImage?を設定します
- makeUIViewControllerでPHPickerViewControllerを作成
- delegateにcoordinatorをセット
- CoordinatorクラスにPHPickerViewControllerDelegateをセットしdelegateメソッドが呼ばれるように設定
- 画像選択後にCoodinatorのdidFinishPickingが呼ばれるのでParent(ここではImagePicker)のimageに画像を渡す
struct ImagePicker:UIViewControllerRepresentable{
//SwiftUIと繋がるBindingオブジェクト
@Binding var image:UIImage?
//Coordinatorでdelegateメソッドを処理して、UIKit側の処理をさせる
class Coordinator:NSObject,PHPickerViewControllerDelegate{
var parent:ImagePicker
init(parent: ImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let provider = results.first?.itemProvider else {return}
if provider.canLoadObject(ofClass: UIImage.self){
provider.loadObject(ofClass: UIImage.self) { image, _ in
self.parent.image = image as? UIImage
}
}
}
}
//ViewControllerの作成:今回はPickerを返す
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.filter = .images
let picker = PHPickerViewController(configuration: config)
//delegateにはselfではなくcoordinatorを渡す
picker.delegate = context.coordinator
return picker
}
//UIViewControllerRepresentable自体のメソッド
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
}
//UIViewControllerRepresentable自体のメソッド
func makeCoordinator() -> Coordinator {
//ImagePickerをparentとしてセット
Coordinator(parent: self)
}
}
SwiftUI側でImagePickerを呼び出す
- ImagePickerをSwiftUIのViewとして呼び出すことができるのでinputImageをバインディング
- バインディングしたinputImageに変化があった場合に処理をするようにonChangeで画像を読み込み、SwiftUI側のimageに画像をセット
struct ContentView: View {
@State private var image:Image?
@State private var inputImage:UIImage?
@State private var showingImagePicker = false
var body: some View {
VStack{
image?
.resizable()
.scaledToFit()
Button {
showingImagePicker = true
} label: {
Text("Select Image")
}
//Buttonが押されたら呼ばれる
}.sheet(isPresented: $showingImagePicker) {
ImagePicker(image: $inputImage)
}//inputImageの変化を監視して変化があればloadImage
.onChange(of: inputImage) { newValue in
loadImage()
}
}
func loadImage(){
guard let inputImage = inputImage else {return}
image = Image(uiImage: inputImage)
}
}
まとめ
- UIViewControllerRepresentableでCoordinatorを使うことでuiKit側のdelegateメソッドが処理できるのでその処理でSwiftUI側の値とバインディングすることで実現できる
なお、今回の内容はこちらで学習した内容です。
環境
・Swift 5.7.2
・Xcode 14.2
・iOS 16.2
おすすめ参考書籍
図とサンプルコードが多くわかりやすく、手を動かしながら学べるのはもちろんですが、状態やデータフローに関する解説や、swiftuiから uikitを使う方法、uikitから swiftuiを使う方法などフレームワークの関連性まで説明していてとても参考になります。
SwiftUIの勉強ならUdemyがおすすめ!
私は以下の講座で勉強しています。サンプルアプリをたくさん作るので楽しく進められます。
2022/12/27時点で4345評価のベストセラーです。
SwiftUI Masterclass 2022https://www.udemy.com/courses/search/?src=ukw&q=SwiftUI
2400円と安いのもおすすめです。
英語ですが、英語のUdemyコースの勉強の仕方は以下で説明しています。簡単です。
もしご参考になりましたら下部にある役に立ったボタン、TwitterなどSNSへの投稿をしていただけると励みになります
コメント