I have a problem with creating a new UIViewControllerRepresentable, as the makeUIViewController method runs only once in UIViewControllerRepresentable, preventing updates to the new view. What would be the optimal way to modify this code while maintaining the privacy of MyView within ControllerView?
private struct ControllerView<Content: View>: View {
struct MyView<ContentM: View>: UIViewControllerRepresentable {
let rootView: ContentM
init(rootView: ContentM) {
self.rootView = rootView
print("init MyView")
}
func makeUIViewController(context: Context) -> UIViewController {
print("makeUI")
/// create my custom VC
return UIHostingController(rootView: rootView)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
print("updateUI")
}
}
let rootView: () -> Content
@Binding var isGreen: Bool
init(isGreen: Binding<Bool>,@ViewBuilder rootView: @escaping () -> Content) {
self.rootView = rootView
self._isGreen = isGreen
}
var body: some View {
ZStack {
MyView(rootView: rootView())
Button {
isGreen.toggle()
} label: {
Text("Change")
}
}
}
}
private struct GreenView: View {
var body: some View {Color.green.ignoresSafeArea()}
}
private struct OrangeView: View {
var body: some View {Color.orange.ignoresSafeArea()}
}
struct SwiftUIView21: View {
@State var isGreen: Bool = true
var body: some View {
ControllerView(isGreen: $isGreen) {
if isGreen {
GreenView()
} else {
OrangeView()
}
}
}
}
#Preview {
SwiftUIView21()
}
While
makeUIViewControlleris not called,updateUIViewControlleris. You can change the view that is displayed in theUIHostingControllerthere.Note that this will break any animations you want to do when you toggle between the two views. SwiftUI can't animate
uiViewController.rootView = rootView.Alternatively, you can change
MyView's id every time a toggle happens:This recreate a new
UIHostingControllerevery time you change views, and can animate the change. However, this only animates the change between twoMyViews, which just so happens to look similar to the animation of changing betweenOrangeViewandGreenView(both a cross-fade). If you have other animations like animating the scale of something:Then the animation will still be a cross-fade, not a scale animation.
A third way I found was to use an
@Observablewrapper to wrap theBool, then put it in theEnvironment.Now the animations are all preserved.