swiftswiftuiuiviewrepresentable

How can I make my SwiftUI wrapper respect UIView size across all iOS versions?


I'm currently working on a SwiftUI wrapper for UIView and UIViewController, and my aim is to make this wrapper respect the size of the UIView and constraints.

For now, I have successfully implemented the sizeThatFits method from the UIViewRepresentable protocol, and it's working as expected. Here's my current implementation of size calculating:

func sizeThatFits(_ width: CGFloat?, _ height: CGFloat?) -> CGSize? {
    let intrinsicContentSize = self.intrinsicContentSize
    let targetSize = CGSize(
        width: width ?? intrinsicContentSize.width,
        height: height ?? intrinsicContentSize.height
    )
    guard targetSize.width != UIView.noIntrinsicMetric, targetSize.height != UIView.noIntrinsicMetric else {
        return nil
    }
    let horizontalPriority: UILayoutPriority = width == nil ? .defaultLow : .defaultHigh
    let verticalPriority: UILayoutPriority = height == nil ? .defaultLow : .defaultHigh
    return systemLayoutSizeFitting(
        targetSize,
        withHorizontalFittingPriority: horizontalPriority,
        verticalFittingPriority: verticalPriority
    )
}

However, this method is only available from iOS 16 onwards. My goal is to provide the same functionality across all iOS versions.

Any suggestions or ideas on how to accomplish this would be greatly appreciated. Thank you!

I have experimented with various constraints, content compression/hugging priorities and fixedSize as suggested in answers to similar questions here, but I have yet to achieve satisfying results.


Solution

  • After a lot of experimentation, I found out that when calculating the size of a view, SwiftUI only refers to intrinsicContentSize property, which in turn does not take into account the desired size (for example, for a UILabel it depends only on the text), so there is no easy way to correctly adjust the size of the view to the desired one, taking into account its content and constraints.
    So the answer is it's not possible without inheritance and overriding intrinsicContentSize.

    P.S. I managed to find some hacks and got the desired result with view wrappers here.
    I can't provide a detailed code example here as it is quite large (multiple classes and structs).