更新 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
}
}
}
我尝试制作带有可替换图像的 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
}
}
}