I am adapting a Swift Project to SwiftUI. The original project has Drag and Drop on UIImages, drawing and some other manipulations which aren't possible in SwiftUI.
The code below is for explaining the problem only. Working code on: https://github.com/rolisanchez/TestableDragAndDrop
On the project, when a user clicks on a button, a @State setChooseImage
is changed to true, opening a sheet in which he is presented with a series of images:
.sheet(isPresented: self.$setChooseImage, onDismiss: nil) {
VStack {
Button(action: {
self.setChooseImage = false
self.chosenAssetImage = UIImage(named: "testImage")
self.shouldAddImage = true
}) {
Image("testImage")
.renderingMode(Image.TemplateRenderingMode?.init(Image.TemplateRenderingMode.original))
Text("Image 1")
}
Button(action: {
self.setChooseImage = false
self.chosenAssetImage = UIImage(named: "testImage2")
self.shouldAddImage = true
}) {
Image("testImage2")
.renderingMode(Image.TemplateRenderingMode?.init(Image.TemplateRenderingMode.original))
Text("Image 2")
}
}
}
After selecting the image, setChooseImage
is set back to false, closing the sheet. The Image self.chosenAssetImage
is also a @State
and is set to the chosen Image. The @State shouldAddImage
is also set to true. This chosen UIImage and Bool are used inside a UIView I created to add the UIImages. It is called inside SwiftUI like this:
DragAndDropRepresentable(shouldAddImage: $shouldAddImage, chosenAssetImage: $chosenAssetImage)
The UIViewRepresentable to add the UIView is the following:
struct DragAndDropRepresentable: UIViewRepresentable {
@Binding var shouldAddImage: Bool
@Binding var chosenAssetImage: UIImage?
func makeUIView(context: Context) -> DragAndDropUIView {
let view = DragAndDropUIView(frame: CGRect.zero)
return view
}
func updateUIView(_ uiView: DragAndDropUIView, context: UIViewRepresentableContext< DragAndDropRepresentable >) {
if shouldAddImage {
shouldAddImage = false
guard let image = chosenAssetImage else { return }
uiView.addNewAssetImage(image: image)
}
}
}
I understand
updateUIView
is called whenever there are some changes that could affect the views. In this case,shouldAddImage
became true, thus entering theif
loop correctly and callingaddNewAssetImage
, which inserts the image into the UIView.The problem here is that
updateUIView
is called multiple times, and enters theif shouldAddImage
loop all those times, before updating theshouldAddImage
Binding. This means that it will add the image multiple times to the UIView.I put a breakpoint before and after the assignment of
shouldAddImage = false
, and even after passing that line, the value continues to betrue
.The behavior I wanted is to change the
shouldAddImage
immediately to false, so that even ifupdateUIView
is called multiple times, it would only enter the loop once, adding the image only once.