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
makeUIViewController
is not called,updateUIViewController
is. You can change the view that is displayed in theUIHostingController
there.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
UIHostingController
every time you change views, and can animate the change. However, this only animates the change between twoMyView
s, which just so happens to look similar to the animation of changing betweenOrangeView
andGreenView
(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
@Observable
wrapper to wrap theBool
, then put it in theEnvironment
.Now the animations are all preserved.