Search code examples
swiftuiuihostingcontrollercoordinator-pattern

How do I fix this layout of a SwiftUI view inside of a UIHostingController?


In my UIKit based app, I have a simple SwiftUI view that my app shows when a screen has no records to show. I'm embedding it in a UIHostingController to do this. The problem is that the contents of the view are shoved off to the upper left corner of the screen:

enter image description here

Here's the code for the SwiftUI view:

struct ContentView: View {
    var body: some View {
        ZStack {
            Color("darkerBlue")
                .ignoresSafeArea()

            VStack(spacing: 20) {
                Image("barbell")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 200, height: 200) // Adjust the image size

                Text("You don't have any lifts saved.")
                    .font(.title)
                    .foregroundColor(.white)
                    .padding()

                Button(action: {
                    // Handle button action
                }) {
                    Text("Do it")
                        .font(.headline)
                        .foregroundColor(.white)
                        .padding(EdgeInsets(top: 8, leading: 50, bottom: 8, trailing: 50))
                        .background(Color("lightBlue"))
                        .cornerRadius(8)
                }
            }
        }
    }
}

If I take that code and put it in a fresh, new SwiftUI project it looks like I'd expect (the styling is in progress):

enter image description here

I create the EmptyLogView and put it in a UIHostingController like this:

        case .noLiftEvents:
            let emptyLogView = EmptyLogView(coordinator: self)
            let hostingController = UIHostingController(rootView: emptyLogView
            add(hostingController)

            return hostingController

'add(hostingController' is a UIViewController extension:

    func add(_ child: UIViewController) {
      
        addChild(child)
        view.addSubview(child.view)
        child.didMove(toParent: self)

I haven't added any constraints to the UIHostingController and I've removed all the view modifiers and added them back one-by-one to find the offender(s) and still the views are shoved into the upper left corner.

I'm new to SwiftUI so maybe I'm missing something obvious. Can anybody explain what's going on and how to fix this?

Thanks


Solution

  • In this method func add(_ child: UIViewController), you correctly added the child.view as a subview of the current ViewController's view:

    view.addSubview(child.view)
    

    However, you didn't set a frame nor give constraints. After add(hostingController), you need to add something like:

    NSLayoutConstraint.activate([
        hostingController.view.topAnchor.constraint(equalTo: self.view.topAnchor),
        hostingController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
        hostingController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
        hostingController.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
    ])