NEW BOOK! Swift Gems: 100+ tips to take your Swift code to the next level. Learn more ...NEW BOOK! Swift Gems:100+ advanced Swift tips. Lear more...
Quick Tip Icon
Quick Tip

Provide custom size for UIViews wrapped in UIViewRepresentable

Starting from iOS 16 the UIViewRepresentable protocol has a new API sizeThatFits(_:uiView:context:) that lets us provide custom sizing logic for wrapped UIViews in SwiftUI apps.

The method gets passed the size proposal and the UIView itself, so we can calculate the desired dimensions or simply return a fixed predefined size.

struct MyUIViewWrapper: UIViewRepresentable {
    ...
    
    func sizeThatFits(
        _ proposal: ProposedViewSize,
        uiView: UITextField, context: Context
    ) -> CGSize? {
        // return calculated size
    }
}

If we return nil or don't define this method at all, the system will fallback to the default sizing algorithm.

Swift Gems by Natalia Panferova book coverSwift Gems by Natalia Panferova book cover

Check out our new book!

Swift Gems

100+ tips to take your Swift code to the next level

Swift Gems

100+ tips to take your Swift code to the next level

  • Advanced Swift techniques for experienced developers bypassing basic tutorials
  • Curated, actionable tips ready for immediate integration into any Swift project
  • Strategies to improve code quality, structure, and performance across all platforms
  • Practical Swift insights from years of development, applicable from iOS to server-side Swift

I found this method useful when wrapping UITextField in SwiftUI, if I want it to respect the frame coming from the SwiftUI code and not overflow the provided width.

struct ContentView: View {
    @State private var text = "Hello, world!"
    
    var body: some View {
        WrappedTextField(text: $text)
            .padding(10)
            .frame(width: 200, height: 50)
            .border(.gray)
    }
}

struct WrappedTextField: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        // set up the text field
        return textField
    }
    
    func sizeThatFits(
        _ proposal: ProposedViewSize,
        uiView: UITextField, context: Context
    ) -> CGSize? {
        guard
            let width = proposal.width,
            let height = proposal.height
        else { return nil }
        
        return CGSize(width: width, height: height)
    }
    
    ...
}

If you are working with both UIKit and SwiftUI in one project, you might like my recent book Integrating SwiftUI into UIKit Apps. It focuses on gradually adopting SwiftUI in UIKit projects and also covers how to start migrating to the SwiftUI app lifecycle while reusing existing UIKit views and components along the way.