Alright, I have tried to follow your advice and I don't see how this can help.
I have this setup:
struct AnimatedView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
let width = viewModel.isExpanded ? 120.0 : 50.0
let height = viewModel.isExpanded ? 400.0 : 100.0
let cornerRadius = viewModel.isExpanded ? 42.0 : 8.0
Color(uiColor: .red)
.frame(width: width, height: height)
.cornerRadius(cornerRadius)
}
}
The hosting controller is mounted to the top of its parent via constraints.
Then I do this in my tap handler for a totally separate button:
@objc func tap() {
withAnimation(Animation.easeInOut(duration: 0.5), {
viewModel.isExpanded.toggle()
})
}
And what I observe here is that my hosting controller's view immediately teleports to the new frame - its center is immediately in the position where it should be only at the end of the animation. Meanwhile, the SwiftUI content is animating correctly, except it has already teleported.
I have tried to use your answer @DTS Engineer
I have assigned hostingController.sizingOptions = [.intrinsicContentSize, .preferredContentSize] and added a KVO observation to the \.preferredContentSize.
observation = hostingController.observe(
\.preferredContentSize,
options: [.new]
) { [weak self] controller, change in
guard let self else { return }
UIView.animate(
withDuration: 0.5,
delay: 0,
options: [.curveEaseInOut],
animations: {
self.view.layoutIfNeeded()
})
}
Because my UIHostingController is laid out via constraints, I don't see what else I can do to animate the content other than to ask for a relayout on the parent.
This however, doesn't work. Also, in the KVO handler of the preferredContentSize, I have found that when the closure is called, the center value has already been set to the final value! So even if I launch UIView.animate, there will be no frame updates in the animation transaction, and nothing will be animated.
You can see the problem I am describing in this video:
https://github.com/user-attachments/assets/bb7c9d7c-ef6a-47d9-85fd-27fcc6f12b13
So I don't think that your answer answers my question. And I would like to inquire once again - what is the correct canonical way to animate the UIHostingController changing its position along with the SwiftUI animation?