iosswiftswiftuiios13uihostingcontroller

Swift UI: UIHostingController.view is not fit to content view size at iOS 13


iOS 13 iOS 14

I want to update Swift UI View according to the communication result. But UIHostingController.view is not fit rootView size at iOS 13. The same thing happens when I try with the sample code below. I want to add self-sizing SwiftUI View to UIStackView, but SwiftUI View overlaps with the previous and next views is occurring because this problem. How can I avoid this problem?

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let object = SampleObject()
        let sampleView = SampleView(object: object)
        let hosting = UIHostingController(rootView: sampleView)
        hosting.view.backgroundColor = UIColor.green
        addChild(hosting)
        view.addSubview(hosting.view)
        hosting.view.translatesAutoresizingMaskIntoConstraints = false
        hosting.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        hosting.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        hosting.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        hosting.didMove(toParent: self)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            object.test()
        }
    }
}


struct SampleView: View {
    @ObservedObject var object: SampleObject
    
    var body: some View {
        VStack {
            Text("test1").background(Color.blue)
            Text("test2").background(Color.red)
            if object.state.isVisibleText {
                Text("test2").background(Color.gray)
            }
        }
        .padding(32)
        .background(Color.yellow)
    }
}


final class SampleObject: ObservableObject {
    struct ViewState {
        var isVisibleText: Bool = false
    }
    
    @Published private(set) var state = ViewState()
    
    func test() {
        state.isVisibleText = true
    }
}

If addSubview to UIStackView as below, the height of Swift UI View will not change in iOS13. enter image description here

iOS13 (incorrect) enter image description here

iOS14 (correct) enter image description here


Solution

  • Only for iOS 13

    Try this:

    Every time the view size change, call this:

    sampleView.view.removeFromSuperview()
    let sampleView = SampleView(object: object)
    let hosting = UIHostingController(rootView: sampleView)
    view.addArrangedSubview(hosting.view)