web-dev-qa-db-ja.com

SwiftUIでImagePickerを開く方法は?

SwiftUIを使用してアプリでImagePickerを開く必要があります。どうすればよいですか?

UIImagePickerControllerを使用することを考えましたが、SwiftUIでそれを行う方法がわかりません。

23
Shahar

より一般的で拡張可能なバージョンを実装しました。私はSubjectではなくBindingを使用して、ビューに別のバインディングを追加することが元に戻せない/不適切であるという問題を解決しました。

たとえば、基盤となるストレージに保存されている一連の画像を表示するListを作成し、画像ピッカーを使用して画像を追加したい場合。この場合、基になるストレージに画像が追加されました。

したがって、私はサブジェクトを使用して画像を転送し、それを観察して新しい画像をストレージに追加するか、またはバインディングのように動作させたい場合は、コードも1行です。 (観察での状態の変更)

次に、設定をViewModelにラップしました。これにより、より多くのサブジェクトまたは構成が必要な場合でも、混乱しないようになっています。

import SwiftUI
import Combine

struct ImagePickerView : UIViewControllerRepresentable {

    @Binding var model: ImagePickerViewModel

    typealias UIViewControllerType = UIImagePickerController

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<Self>) -> UIImagePickerController {

        let controller = UIImagePickerController()
        controller.delegate = context.coordinator
        controller.allowsEditing = false
        controller.mediaTypes = ["public.image"]
        controller.sourceType = .photoLibrary
        return controller

    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePickerView>) {
        // run right after making

    }

    class Coordinator : NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

        var parentView: ImagePickerView

        init(_ parentView: ImagePickerView) {
            self.parentView = parentView
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parentView.model.isPresented = false
        }

        func imagePickerController(_ picker: UIImagePickerController,
                                          didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {

            guard let uiImage = info[.originalImage] as? UIImage else { return }

            let image = Image(uiImage: uiImage)
            parentView.model.pickedImagesSubject?.send([image])
            parentView.model.isPresented = false

        }

    }

}

struct ImagePickerViewModel {
    var isPresented: Bool = false
    let pickedImagesSubject: PassthroughSubject<[Image], Never>! = PassthroughSubject<[Image], Never>()
}

使用法:

struct SomeView : View {

    @EnvironmentObject var storage: Storage
    @State var imagePickerViewModel = ImagePickerViewModel()

    var body: some View {
        Button(action: { self.imagePickerViewModel.isPresented.toggle() }) { ... }
            .sheet(isPresented: $imagePickerViewModel.isPresented) {
                ImagePickerView(model: self.$imagePickerViewModel)
            }
            .onReceive(imagePickerViewModel.pickedImagesSubject) { (images: [Image]) -> Void in
                withAnimation {
                    // modify your storage here
                    self.storage.images += images
                }
            }
    }
}
0
cayZ

私はそれを次のように実装しました:

    import SwiftUI

    final class ImagePickerCoordinator: NSObject {

        @Binding var image: UIImage?
        @Binding var takePhoto: Bool

        init(image: Binding<UIImage?>, takePhoto: Binding<Bool>) {
            _image = image
            _takePhoto = takePhoto
        }
    }

    struct ShowImagePicker: UIViewControllerRepresentable {

        @Binding var image: UIImage?
        @Binding var takePhoto: Bool

        func makeCoordinator() -> ImagePickerCoordinator {
            ImagePickerCoordinator(image: $image, takePhoto: $takePhoto)
        }

        func makeUIViewController(context: Context) -> UIImagePickerController {

            let pickerController = UIImagePickerController()
            pickerController.delegate = context.coordinator

            guard UIImagePickerController.isSourceTypeAvailable(.camera) else { return pickerController }

            switch self.takePhoto {
            case true:
                pickerController.sourceType = .camera
            case false:
                pickerController.sourceType = .photoLibrary
            }

            pickerController.allowsEditing = true
            return pickerController
        }

        func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
    }

    extension ImagePickerCoordinator: UINavigationControllerDelegate, UIImagePickerControllerDelegate {

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

            guard let uiImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }

            self.image = uiImage
            picker.dismiss(animated: true, completion: nil)
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            picker.dismiss(animated: true, completion: nil)
        }

}

たった2つのボタンのロジックをビューに追加すれば十分です...))

0
Dim Novo

私はSwiftで非常に新しいですが、次のようにしてそれを得ることができました。

これにより、イメージピッカーモーダルが読み込まれ、写真を選択できます。次に、親から@State変数を更新します。

これで問題が解決した場合は、@State@EnvironmentObjectなどの複数のコンポーネントにまたがることができるものに置き換えて、他のコンポーネントも更新できるようにすることができます。

お役に立てれば!

// ImagePicker.Swift

struct ImagePicker : View {   
    @State var image: UIImage? = nil

    var body: some View {
        ImagePickerViewController(image: $image)
    }
}
// ImagePickerViewController.Swift

import UIKit
import AVFoundation
import SwiftUI


struct ImagePickerViewController: UIViewControllerRepresentable {
    @Binding var image: UIImage?

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePickerViewController>) {
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerViewController>) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
        imagePicker.allowsEditing = false
        imagePicker.delegate = context.coordinator
        return imagePicker
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVCapturePhotoCaptureDelegate {

        var parent: ImagePickerViewController

        init(_ parent: ImagePickerViewController) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            let imagePicked = info[.originalImage] as! UIImage            
            parent.image = imagePicked
            picker.dismiss(animated: true, completion: nil)
        }
    }
}

使用法:

// SampleView.Swift

struct SampleView : View {
    var body: some View {
        PresentationLink(destination: ImagePicker().environmentObject(self.userData), label: {
           Text("Import Photo")
       })
    }
}

繰り返しになりますが、Swiftに慣れているので、コメントがありましたらお知らせください!詳細をお知らせください。

0
jkusachi