swiftui - 如何在 SwiftUI 中对 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()
}
}
内容视图
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:)
which 在 iOS 14 上可能会出现问题,因为它会加载它的第一个渲染的工作表内容(在您的情况下,ImagePicker
对于第一个图像),然后不会像预期的那样更新(请参阅例如 SwiftUI @State 和 .sheet() ios13 vs ios14)。
解决方案是使用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
功能,因为这里没有必要,但是如果您确实需要它来进行真正的实现,我建议您onDisappear
在个人ImagePicker
s 上使用它,这样您就可以区分哪个被解雇了。
推荐阅读
- c++ - 动态加载 dll 并使用其类方法
- javascript - 如何在 redux 中控制布尔值?
- react-native - 如何找到两个元素 React Native 之间的距离?
- java - 一行在spring boot Jpa .findall()响应restfull api中重复多次
- wpf - 从资源字典中的事件处理程序调用 Viewmodel 方法
- python - 在 Keras 中使用 CNN 模型获得非常差的准确性
- r - 在R中绘制不同颜色的时间序列
- python - 如何散列一个矩阵
- .net - Trace.CorrelationManager.ActivityId 的 ECS 字段引用中的等价物是什么?
- c# - C# 使用动态键反序列化 JSON