ホーム » Swift » 【SwiftUI】ImagePickerの実装方法(フォトライブラリ)

【SwiftUI】ImagePickerの実装方法(フォトライブラリ)

Swift

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 2022 icon
https://www.udemy.com/courses/search/?src=ukw&q=SwiftUI

2400円と安いのもおすすめです。

英語ですが、英語のUdemyコースの勉強の仕方は以下で説明しています。簡単です。

もしご参考になりましたら下部にある役に立ったボタン、TwitterなどSNSへの投稿をしていただけると励みになります

コメント

タイトルとURLをコピーしました