0

Problem

Hello, I need help with a SwiftUI View that is presented by a View Controller that is configured in a storyboard.

I present a SwiftUI View including its own model using a UIHostingController as described in this post: addSubView SwiftUI View to UIKit UIView in Swift.

Now my view is shrunken inside its Hosting View Controller's view property to its content size.

What I have tried

  • Wrapping a ContainerView inside the Parent View Controller into two StackViews to force the view to use the whole screen (vertical and horizontal)
  • Configuring the initial VStack inside my SwiftUI View with .frame(minWidth: 0, maxWidth: .infinity)
  • Using an initial HStack with a Spacer() beneath and below all elements within that stack as suggested in Make a VStack fill the width of the screen in SwiftUI

Some Code

View Controller:

class SomeParentViewController: UIViewController {

    var detailsView: DetailsOverlayView?                   //  --> SwiftUI View
    var detailsViewModel: DetailsOverlayViewModel?         //  --> Its model
    var childVC: UIHostingController<DetailsOverlayView>?  //  --> Child VC to present View
                                                           //      inside UIView
    var detailData: DetailData?
    

    override func viewDidLoad() {

        super.viewDidLoad()

        if let data = detailData {
            model = DetailsOverlayViewModel(data: data)
        }

        if let m = model {
            detailsView = DetailsOverlayView(viewModel: m)
        }

        if let v = paymentDetailsView {
            child = UIHostingController(rootView: v)
            child?.view.translatesAutoresizingMaskIntoConstraints = false
            child?.view.frame = self.view.bounds
        }
    }

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)

        if let cvc = childVC {
            self.addSubview(cvc.view)
            self.addChild(cvc)
        }
    }
    ...
}

The SwiftUI View:

...
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            // Title
            HStack {
                Text("My great and awesome title")
            }
            VStack(alignment: .leading, spacing: 0) {
                Text("My even more awesome subtitle")
                HStack(alignment: .top) {
                    Text("on the left 1")
                    Spacer()
                    Text("on the right 1")
                }
                HStack(alignment: .top) {
                    Text("on the left 2")
                    Spacer()
                    Text("on the right 2")
                }
                Divider()
            }
        }
        .frame(minWidth: 0, maxWidth: .infinity)
        .padding(16)
    }
...

A Picture of the Result

This picture shows that my View is limited to its content's size by the Hosting View Controller, although the Hosting View Controller should use the size of its Parent View which is the size of the Parent View Controller which again equals the full screen size.

LuGeNat
  • 179
  • 1
  • 2
  • 13

1 Answers1

0

Well considering a SwiftUI view wrapped in a UIHostingController acts the same way a UIViewController does, you would define autolayout constraints the same way.

Having declared translatesAutoresizingMaskIntoConstraints = false, I'm going to assume that's the plan. In that case, what I'd suggest is the following:

NSLayoutConstraint.activate([
  child.view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
  child.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
  child.view.widthAnchor.constraint(equalTo: self.view.widthAnchor),
  child.view.heightAnchor.constraint(equalTo: self.view.heighAnchor)
])

The above makes the UIHostingController the same size as the parent controller and centered to it. The height and width anchors can be constants such that you'd do .constraint(equalToConstant: 150), or whatever other variation you'd prefer.

thanat0sis
  • 185
  • 1
  • 12
  • Of course you can also choose not to declare some of the anchors, like the height one in your example where you can just set it to 0 initially and stretch it to content. – thanat0sis May 18 '21 at 20:09