Как открыть ImagePicker в SwiftUI? - PullRequest
8 голосов
/ 09 июня 2019

Мне нужно открыть ImagePicker в моем приложении с помощью SwiftUI, как я могу это сделать?

Я думал об использовании UIImagePickerController, но я не знаю, как это сделать в SwiftUI.

Ответы [ 4 ]

6 голосов
/ 09 июня 2019

Вот реализация "грубо по краям".

Вам нужно обернуть UIImagePickerController в структуру, реализующую UIViewControllerRepresentable.

Для получения дополнительной информации о UIViewControllerRepresentable, пожалуйста, проверьте этот удивительный доклад WWDC 2019:

Интеграция SwiftUI

struct ImagePicker: UIViewControllerRepresentable {

    let isShown: Binding<Bool>
    let image: Binding<Image?>

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

        let isShown: Binding<Bool>
        let image: Binding<Image?>

        init(isShown: Binding<Bool>, image: Binding<Image?>) {
            self.isShown = isShown
            self.image = image
        }

        func imagePickerController(_ picker: UIImagePickerController,
                                   didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
            image.value = Image(uiImage: uiImage)
            isShown.value = false
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            isShown.value = false
        }

    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(isShown: isShown, image: image)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }

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

    }

}

Вот простой способ проверить это.

Это грубо в том смысле, что:

  • сборщик отображается прямо в верхней части представления, без перехода
  • выбранное изображение появляется без какой-либо анимации и заменяет кнопку Show image picker
struct ContentView: View {

    @State var showImagePicker: Bool = false
    @State var image: Image?

    var body: some View {
        ZStack {
            VStack {
                Button(action: {
                    withAnimation {
                        self.showImagePicker.toggle()
                    }
                }) {
                    Text("Show image picker")
                }
                image?.resizable().frame(width: 100, height: 100)
            }
            if (showImagePicker) {
                ImagePicker(isShown: $showImagePicker, image: $image)
            }
        }
    }

}

Надеюсь, это поможет в качестве отправной точки!

Я уверен, что Apple сделает это проще, когда SwiftUI выйдет из бета-версии.

enter image description here

0 голосов
/ 23 июля 2019

Вот версия, которая работает в Xcode 11 beta 4.

Он использует синглтон BindableObject (ImagePicker.shared) с двумя свойствами: .view и .image.

См. Использование ниже (ImagePickerTestView)

import SwiftUI
import Combine

final class ImagePicker : BindableObject {

    static let shared : ImagePicker = ImagePicker()

    private init() {}  //force using the singleton: ImagePicker.shared

    let view = ImagePicker.View()
    let coordinator = ImagePicker.Coordinator()

    // Bindable Object part
    let willChange = PassthroughSubject<Image?, Never>()

    @Published var image: Image? = nil {
        didSet {
            if image != nil {
                willChange.send(image)
            }
        }
    }
}


extension ImagePicker {

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

        // UIImagePickerControllerDelegate
        func imagePickerController(_ picker: UIImagePickerController,
                                   didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
            ImagePicker.shared.image = Image(uiImage: uiImage)
            picker.dismiss(animated:true)
        }

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


    struct View: UIViewControllerRepresentable {

        func makeCoordinator() -> Coordinator {
            ImagePicker.shared.coordinator
        }

        func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker.View>) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.delegate = context.coordinator
            return picker
        }

        func updateUIViewController(_ uiViewController: UIImagePickerController,
                                    context: UIViewControllerRepresentableContext<ImagePicker.View>) {

        }

    }

}


struct ImagePickerTestView: View {

    @State var showingPicker = false

    @State var image : Image? = nil
    // you could use ImagePicker.shared.image directly

    var body: some View {
        VStack {
            Button("Show image picker") {
                self.showingPicker = true
            }

            image?
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 300)

        }.sheet(isPresented: $showingPicker,
                onDismiss: {
                    // do whatever you need here
                }, content: {
                    ImagePicker.shared.view
                })
        .onReceive(ImagePicker.shared.$image) { image in
            // This gets called when the image is picked.
            // sheet/onDismiss gets called when the picker completely leaves the screen
            self.image = image
        }
    }

}

#if DEBUG
struct ImagePicker_Previews : PreviewProvider {

    static var previews: some View {
        ImagePickerTestView()
    }
}
#endif
0 голосов
/ 20 июля 2019

Я очень новичок в Свифте, но я смог получить его с помощью следующего.

Это загрузит модальное средство выбора изображения и позволит выбрать фотографию, а затем обновит переменную @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 голосов
/ 29 июня 2019

таким образом вы получаете модальный переход и лучшую опциональную обработку, но не забудьте управлять увольнением в обертке сборщика

Group {
        PresentationButton(destination: ImagePicker(image: $image)) {
            Text("Seleziona Immagine")
        }

        image.map {
            $0
            .resizable()
            .frame(width: 100, height: 100)
        }
    }
...