I think I need to change a boolean in a UIRepresentableView
before removing it from the ContentView
but can't find a way, since I can't mutate the struct properties.
Why do I need that? Because I need to prevent updateUIView()
from being called one last time before the view being released.
So probably this is an XY problem... anyway, I'm lost.
I have a model like this:
class PlayerModel: NSObject, ObservableObject {
@Published var lottie: [LottieView]
Where LottieView
is this:
struct LottieView: UIViewRepresentable {
var name: String
var loopMode: LottieLoopMode = .playOnce
func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
let view = UIView()
return view
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {
uiView.subviews.forEach({ sub in
sub.removeFromSuperview()
})
let animationView = AnimationView()
animationView.translatesAutoresizingMaskIntoConstraints = false
uiView.addSubview(animationView)
NSLayoutConstraint.activate([
animationView.widthAnchor.constraint(equalTo: uiView.widthAnchor),
animationView.heightAnchor.constraint(equalTo: uiView.heightAnchor)
])
animationView.animation = Animation.named(name, animationCache: LRUAnimationCache.sharedCache)
animationView.contentMode = .scaleAspectFit
animationView.loopMode = loopMode
animationView.play()
}
}
In my ContentView
I only display a LottieView
if there's a recent one in the published array:
struct ContentView: View {
@ObservedObject var model: PlayerModel
var body: some View {
NavigationView {
VStack {
// ...
if let lottie = model.lottie.last {
lottie
}
// ...
}
}
}
}
Now this works ok, but when in the model I remove the last LottieView
from the published array, the updateUIView()
func is called one last time by SwiftUI, resulting in the animation being recreated again just before the LottieView
is removed from the view, resulting in a visible flicker.
So I thought I'd add a boolean that I could update just before removing the last LottieView
from the published array, and do an if/else in the updateUIView()
, but... is this even possible? I can't find a way.
Ideally I would just have the animation view created in makeUIView()
and nothing done in updateUIView()
but this is not possible, I need to remove the subviews first, otherwise the previous shown animation is not replaced by the new one.
While I would still love to have someone give me a proper solution to my issue, or tell me an alternative way of doing things, I found a workaround.
In the model, I was previously emptying the published array by doing
But if instead we do this:
We see no flicker anymore (however
updateView()
is still called!!).