9
votes

I'm wanting to use a SwiftUI View as content for a child UIView (which in my app would be inside UIViewController) by passing SwiftUI. However the SwiftUI View doesn't respond to state changes once embedded inside UIView.

I created the simplified version of my code below that has the issue. When tapping the Text View embedded inside the EmbedSwiftUIView the outer Text View at the top VStack updates as expected but the Text View embedded inside the EmbedSwiftUIView does not update its state.

struct ProblemView: View {

    @State var count = 0

    var body: some View {
        VStack {
            Text("Count is: \(self.count)")
            EmbedSwiftUIView {
                Text("Tap to increase count: \(self.count)")
                    .onTapGesture {
                        self.count = self.count + 1
                }
            }
        }
    }
}

struct EmbedSwiftUIView<Content:View> : UIViewRepresentable {

    var content: () -> Content

    func makeUIView(context: UIViewRepresentableContext<EmbedSwiftUIView<Content>>) -> UIView {
        let host = UIHostingController(rootView: content())
        return host.view
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<EmbedSwiftUIView<Content>>) {

    }
}
1
Since UIHostingController is for embedding SwiftUI Views in the UIKit world, I wonder if I understand your question correctly. In case you mean something else, which is why does it not update using UIViewRepresentable – this could be the solution: Utitlize func updateUIView() to dig into your UIKit and find your UIKit element to update manually. I know you have a Text() inside your UIKit Representable. This however might be excluded from updating because of the SwiftUI diffing mechanisms, which might not attempt to look for SwiftUI embedded in UIKit. Hope you get my point.HelloTimo

1 Answers

3
votes

Update view or view controller in updateUIView or updateUIViewController function. In this case, using UIViewControllerRepresentable is easier.

struct EmbedSwiftUIView<Content: View> : UIViewControllerRepresentable {

    var content: () -> Content

    func makeUIViewController(context: Context) -> UIHostingController<Content> {
        UIHostingController(rootView: content())
    }

    func updateUIViewController(_ host: UIHostingController<Content>, context: Context) {
        host.rootView = content() // Update content
    }
}