UIViewRepresentable automatic size - Passing UIKit UIView size to SwiftUI
Asked Answered
Q

1

27

Assume you have a UIKit view that wants to decide about its own size (via intrinsicContentSize or layout constraints, the size might change). For example:

/// Some UIKit view that wants to have a specific size
class YellowBoxUIKitView : UIView {

    init() {
        super.init(frame: .zero)
        self.backgroundColor = .yellow
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) is not supported")
    }

    override var intrinsicContentSize: CGSize {
        return CGSize(width: 100, height: 100)
    }

}

How can you wrap this as a SwiftUI UIViewRepresentable and make it pass on the UIView size to SwiftUI automatically?

struct YellowBoxView : UIViewRepresentable {

    func makeUIView(context: Context) -> YellowBoxUIKitView {
        // TODO: How do you pass the size from UIKit up to SwiftUI?
        YellowBoxUIKitView()
    }

    func updateUIView(_ uiView: YellowBoxUIKitView, context: Context) {
    }

}

SwiftUI does not respect the size of the UIView and just give it maximum possible width/height.

Runnable example: SizedUIViewRepresentableView

There is a similiar question asked for a UITextView here: Update UIViewRepresentable size from UIKit in SwiftUI

Qualifier answered 16/5, 2020 at 5:17 Comment(0)
J
27

The solution is to set explicitly compression/hugging priority for represented UIView

Tested with Xcode 11.4 / iOS 13.4

struct YellowBoxView : UIViewRepresentable {

    func makeUIView(context: Context) -> YellowBoxUIKitView {
        let view = YellowBoxUIKitView()

        view.setContentHuggingPriority(.required, for: .horizontal) // << here !!
        view.setContentHuggingPriority(.required, for: .vertical)

        // the same for compression if needed

        return view
    }

    func updateUIView(_ uiView: YellowBoxUIKitView, context: Context) {
    }
}
Jupon answered 16/5, 2020 at 7:8 Comment(4)
Just a note, looks like this strategy doesn't work for UIStackViews. Seems like stacks always take all the area available to them.Chukker
Replacing the two setContentHuggingPriority with view.translatesAutoresizingMaskIntoConstraints = false in the makeUIView worked for me.Attractant
For stack views we solved using the UIKit view's intrinsicContentSize: stackView.layoutIfNeeded(); return CGSize(width: stackView.frame.size.width, height: stackView.frame.size. height)Decastro
Doesn't seem to work if using makeUIViewController. Tried uiViewController.view.setContentCompressionResistance and it had no effect.Binette

© 2022 - 2024 — McMap. All rights reserved.