Ich muss den ImagePicker in meiner App mit SwiftUI öffnen. Wie kann ich das tun?
Ich habe über die Verwendung des UIImagePickerController nachgedacht, weiß aber nicht, wie das in SwiftUI geht.
Ich habe eine Version implementiert, die meiner Meinung nach allgemeiner und erweiterbarer ist. Ich habe ein Subject
anstelle eines Binding
verwendet, um das Problem zu lösen, bei dem es nicht rückgängig gemacht/unangemessen ist, Ihrer Ansicht eine weitere Bindung hinzuzufügen.
Sie haben beispielsweise ein List
erstellt, das eine Reihe von Bildern zeigt, die im zugrunde liegenden Speicher gespeichert sind, und Sie wollten mit der Bildauswahl ein Bild hinzufügen. In diesem Fall ist es sehr schwierig/hässlich, dies zu haben Bild zu Ihrem zugrunde liegenden Speicher hinzugefügt.
Ich habe also ein Motiv verwendet, um das Bild zu übertragen, und Sie können es einfach beobachten und die neuen Bilder einem Speicher hinzufügen. Wenn Sie möchten, dass es sich wie eine Bindung verhält, ist es auch eine Codezeile. (Ändern Sie Ihren Zustand in Ihrer Beobachtung)
Dann habe ich die Einstellungen in ein ViewModel
verpackt, damit es nicht unübersichtlich wird, wenn Sie mehr Themen oder Konfigurationen haben möchten.
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>()
}
Verwendung:
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
}
}
}
}
Ich habe es so implementiert:
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)
}
}
Fügen Sie Ihrer Ansicht die Logik von nur zwei Schaltflächen hinzu, die ausreicht ...))
Ich bin sehr neu bei Swift, aber ich konnte es mit den folgenden bekommen.
Dadurch wird ein Bildauswahlmodal geladen und Sie können ein Foto auswählen. Anschließend wird eine @State
- Variable eines übergeordneten Elements aktualisiert.
Wenn dies für Sie funktioniert, können Sie @State
Durch etwas ersetzen, das sich über mehrere Komponenten erstrecken kann, z. B. @EnvironmentObject
, Damit auch andere Komponenten aktualisiert werden können.
Hoffe das hilft!
// 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)
}
}
}
Verwendung:
// SampleView.Swift
struct SampleView : View {
var body: some View {
PresentationLink(destination: ImagePicker().environmentObject(self.userData), label: {
Text("Import Photo")
})
}
}
Ich bin wieder einmal frisch in Swift). Wenn also jemand Kommentare hat, lass es mich wissen! Freut mich, mehr zu erfahren.