更新 UIImageView 中的图像

Update image in UIImageView

我尝试制作带有可替换图像的 UIKit 元素,我可以像 swiftUI 元素一样使用它。

我现在卡住了,当 UIImageView 中的图像应该使用来自 ObservableObject 的 imageInBlackBox 刷新时。选择图像后,我尝试从 updateUIView 和 imagePickerController 设置新的 imageInBlackBox。但是这两种方法都不会更新 UIImageView,它仅适用于我用于测试的 swiftUI Image 元素。

如何让 imageView.image 在 imageInBlackBox 更改后刷新?

  //Data model
      struct imageAdderDataHolder: Identifiable, Hashable {
            var id: UUID = UUID()
            var isShowingImagePicker:Bool = false
            var imageInBlackBox:UIImage = UIImage(systemName: "photo")! // image for replace
            var height: CGFloat = 160
            var width: CGFloat = 160
        }
        //Data storage
        class imageAdderData: ObservableObject{
            init() {}
            static let shared = imageAdderData()
            @Published var img1: imageAdderDataHolder = imageAdderDataHolder()
        }
        
        struct simpleadder: UIViewRepresentable{
            @ObservedObject var imageData: imageAdderData = .shared
            let mainView: UIView = UIView()
            var imageView: UIImageView = UIImageView()
            
            func makeUIView(context: Context) -> UIView {
                imageView.image = imageData.img1.imageInBlackBox
                imageView.frame.size.width = imageData.img1.width
                imageView.frame.size.height = imageData.img1.height
                imageView.contentMode = .scaleAspectFit
                mainView.addSubview(imageView)
                return mainView
            }
            
            func updateUIView(_ uiView: UIView, context: Context) {
                imageView.image = imageData.img1.imageInBlackBox // try to replace image
            }
        }
        // swiftui view for test
        struct  photoadder: View {
            @ObservedObject var imageData: imageAdderData = .shared
            var body: some View {
                VStack{
                    HStack{
                        simpleadder()
                            .frame(width: imageData.img1.width, height: imageData.img1.height)
                            .border(Color.black, width:1)
                            .sheet(isPresented: $imageData.img1.isShowingImagePicker, content: {
                                imagePickerUIView(isPresented: $imageData.img1.isShowingImagePicker)
                            })
                        Image(uiImage: imageData.img1.imageInBlackBox) // working element for test
                            .resizable()
                            .aspectRatio(contentMode: ContentMode.fit)
                            .frame(width: imageData.img1.width, height: imageData.img1.height)
                            .border(Color.black, width: 1)
                    }
                    Button("change image") {
                        imageData.img1.isShowingImagePicker = true
                    }
                }
            }
        }
        
        
        struct imagePickerUIView: UIViewControllerRepresentable {
            @ObservedObject var imageData: imageAdderData = .shared
            @Binding var isPresented: Bool
            func makeUIViewController(context:
                                        UIViewControllerRepresentableContext<imagePickerUIView>) ->
            UIViewController {
                let controller = UIImagePickerController()
                controller.delegate = context.coordinator
                return controller
            }
            
            func makeCoordinator() -> imagePickerUIView.Coordinator {
                return Coordinator(parent: self)
            }
            
            class Coordinator: NSObject, UIImagePickerControllerDelegate,
                               UINavigationControllerDelegate {
                
                let parent: imagePickerUIView
                init(parent: imagePickerUIView) {
                    self.parent = parent
                }
                
                func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:
                                            [UIImagePickerController.InfoKey : Any]) {
                    if let selectedImageFromPicker = info[.originalImage] as? UIImage {
// try to replace image
                        parent.imageData.img1.imageInBlackBox = selectedImageFromPicker
                    }
                    self.parent.isPresented = false
                }
            }
            func updateUIViewController(_ uiViewController:
                                            imagePickerUIView.UIViewControllerType, context:
                                                UIViewControllerRepresentableContext<imagePickerUIView>) {
            }
        }

这是一个解决方案 - 在可表示的情况下,所有视图都应在 makeUIView 内创建,因为可以(并且通常会)在父更新时重新创建结构(因此内部实例也将被重新创建,同时制作 UIKit视图生命周期持续存在)。

测试 Xcode 12.4 / iOS 14.4.

固定代码:

struct simpleadder: UIViewRepresentable{
    @ObservedObject var imageData: imageAdderData = .shared

    func makeUIView(context: Context) -> UIView {
        let mainView: UIView = UIView()               // << create here !!
        let imageView: UIImageView = UIImageView()    // << create here !!
        imageView.image = imageData.img1.imageInBlackBox
        imageView.frame.size.width = imageData.img1.width
        imageView.frame.size.height = imageData.img1.height
        imageView.contentMode = .scaleAspectFit
        mainView.addSubview(imageView)
        return mainView
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        // find needed view in run-time
        if let imageView = uiView.subviews.first as? UIImageView {
            imageView.image = imageData.img1.imageInBlackBox
        }
    }
}