如何在 SwiftUI 中对 Imagepicker 进行两次单独调用?
How do I make two separate calls to an Imagepicker in SwiftUI?
我希望用户能够将两个单独的图像上传到同一视图的两个不同部分。
我能够让第一张图片正确显示在顶部。但是每当用户添加第二张图片时,顶部的图片会再次更新,而不是底部的图片。
Screenshot
下面是我的代码。如有任何帮助,我们将不胜感激!
ImagePicker
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
ContentView
import SwiftUI
struct ContentView: View {
@State private var firstImage: Image? = Image("PlaceholderImage")
@State private var secondImage: Image? = Image("PlaceholderImage")
@State private var inputImage1: UIImage?
@State private var inputImage2: UIImage?
@State private var showingImagePicker = false
var body: some View {
VStack{
Form {
Section(header: Text("First Image")){
firstImage!
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.showingImagePicker = true }
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage1) {
ImagePicker(image: self.$inputImage1)
}
}
Section(header: Text("Second Image")){
secondImage!
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.showingImagePicker = true }
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage2) {
ImagePicker(image: self.$inputImage2)
}
}
}
}
}
func loadImage1() {
guard let inputImage = inputImage1 else { return }
firstImage = Image(uiImage: inputImage)
}
func loadImage2() {
guard let inputImage = inputImage2 else { return }
secondImage = Image(uiImage: inputImage)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
问题的根本原因是使用 sheet(isPresented:)
这在 iOS 14 上可能会出现问题,因为它加载了它的第一个渲染的 sheet 内容(在你的情况下,第一张图片的 ImagePicker
),然后没有像预期的那样更新(例如,参见 )。
解决方案是使用sheet(item:)
。在您的情况下,这还涉及一些其他重构以使事情按预期工作。这是我想出的:
struct ContentView: View {
@State private var inputImage1: UIImage?
@State private var inputImage2: UIImage?
@State private var activeImagePicker : ImagePickerIdentifier? = nil
enum ImagePickerIdentifier : String, Identifiable {
case picker1, picker2
var id : String {
return self.rawValue
}
}
var image1 : Image {
if let inputImage1 = inputImage1 {
return Image(uiImage: inputImage1)
} else {
return Image("Placeholder")
}
}
var image2 : Image {
if let inputImage2 = inputImage2 {
return Image(uiImage: inputImage2)
} else {
return Image("Placeholder")
}
}
var body: some View {
VStack{
Form {
Section(header: Text("First Image")){
image1
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.activeImagePicker = .picker1 }
}
Section(header: Text("Second Image")) {
image2
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.activeImagePicker = .picker2 }
}
}
.sheet(item: $activeImagePicker) { picker in
switch picker {
case .picker1:
ImagePicker(image: $inputImage1)
case .picker2:
ImagePicker(image: $inputImage2)
}
}
}
}
}
请注意,我去掉了你的 onDismiss
函数,因为它在这里是不必要的,但如果你 确实 需要它来实现你的实际实现,我建议在个人 ImagePicker
上使用 onDisappear
,这将让您区分哪个被解雇。
我希望用户能够将两个单独的图像上传到同一视图的两个不同部分。
我能够让第一张图片正确显示在顶部。但是每当用户添加第二张图片时,顶部的图片会再次更新,而不是底部的图片。
Screenshot
下面是我的代码。如有任何帮助,我们将不胜感激!
ImagePicker
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
ContentView
import SwiftUI
struct ContentView: View {
@State private var firstImage: Image? = Image("PlaceholderImage")
@State private var secondImage: Image? = Image("PlaceholderImage")
@State private var inputImage1: UIImage?
@State private var inputImage2: UIImage?
@State private var showingImagePicker = false
var body: some View {
VStack{
Form {
Section(header: Text("First Image")){
firstImage!
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.showingImagePicker = true }
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage1) {
ImagePicker(image: self.$inputImage1)
}
}
Section(header: Text("Second Image")){
secondImage!
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.showingImagePicker = true }
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage2) {
ImagePicker(image: self.$inputImage2)
}
}
}
}
}
func loadImage1() {
guard let inputImage = inputImage1 else { return }
firstImage = Image(uiImage: inputImage)
}
func loadImage2() {
guard let inputImage = inputImage2 else { return }
secondImage = Image(uiImage: inputImage)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
问题的根本原因是使用 sheet(isPresented:)
这在 iOS 14 上可能会出现问题,因为它加载了它的第一个渲染的 sheet 内容(在你的情况下,第一张图片的 ImagePicker
),然后没有像预期的那样更新(例如,参见
解决方案是使用sheet(item:)
。在您的情况下,这还涉及一些其他重构以使事情按预期工作。这是我想出的:
struct ContentView: View {
@State private var inputImage1: UIImage?
@State private var inputImage2: UIImage?
@State private var activeImagePicker : ImagePickerIdentifier? = nil
enum ImagePickerIdentifier : String, Identifiable {
case picker1, picker2
var id : String {
return self.rawValue
}
}
var image1 : Image {
if let inputImage1 = inputImage1 {
return Image(uiImage: inputImage1)
} else {
return Image("Placeholder")
}
}
var image2 : Image {
if let inputImage2 = inputImage2 {
return Image(uiImage: inputImage2)
} else {
return Image("Placeholder")
}
}
var body: some View {
VStack{
Form {
Section(header: Text("First Image")){
image1
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.activeImagePicker = .picker1 }
}
Section(header: Text("Second Image")) {
image2
.resizable()
.aspectRatio(contentMode: .fit)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 200, alignment: .center)
.clipShape(Rectangle())
.onTapGesture { self.activeImagePicker = .picker2 }
}
}
.sheet(item: $activeImagePicker) { picker in
switch picker {
case .picker1:
ImagePicker(image: $inputImage1)
case .picker2:
ImagePicker(image: $inputImage2)
}
}
}
}
}
请注意,我去掉了你的 onDismiss
函数,因为它在这里是不必要的,但如果你 确实 需要它来实现你的实际实现,我建议在个人 ImagePicker
上使用 onDisappear
,这将让您区分哪个被解雇。