TechnologiesSwiftUI

UIViewRepresentable protocol

iOSmacOStvOSwatchOSvisionOS✓ renders

A wrapper for a UIKit view that you use to integrate that view into your

How it works

UIViewRepresentable is the bridge that lets a UIKit view live inside a SwiftUI layout. When SwiftUI doesn't offer a native equivalent for some control or platform view, you conform a type to UIViewRepresentable and SwiftUI treats the wrapped UIView as a first-class view it can size, position, and update. Reach for it whenever you need to embed UIKit-only functionality and have it participate in the SwiftUI view hierarchy and update cycle.

  1. Conform a view type to UIViewRepresentable

    The protocol is what turns an ordinary struct into a SwiftUI view backed by UIKit. Declaring struct SpinnerView: UIViewRepresentable gives the type a body-free conformance to View, so it can be used anywhere a SwiftUI view is expected — here SpinnerView() sits directly in the layout.

  2. Create the UIKit view in makeUIView(context:)

    SwiftUI calls makeUIView(context:) once to build the underlying view, and its return type fixes the associated UIViewType for the conformance. In the example it returns a UIActivityIndicatorView, configured up front with UIActivityIndicatorView(style: .large), view.startAnimating(), and view.color = .systemBlue before handing the instance back to SwiftUI.

  3. Reflect state changes in updateUIView(_:context:)

    Whenever the relevant SwiftUI state changes, SwiftUI calls updateUIView(_:context:) with the existing view so you can push the new values onto it. The spinner has no driving state, so updateUIView(_ uiView: UIActivityIndicatorView, context: Context) is left empty — but this is the hook where bound data would flow into the UIKit view.

  4. Read the environment through Context

    Both methods receive a Context carrying the current SwiftUI environment, transaction, and (when declared) coordinator. Even unused, the context parameter is the channel through which SwiftUI-managed values reach your UIKit code during creation and every update.

  5. Apply SwiftUI modifiers to the wrapped view

    Because the conformance makes the type a real SwiftUI view, standard modifiers apply to it like any other. The .frame(width: 80, height: 80) attached to SpinnerView() constrains the embedded UIActivityIndicatorView within the surrounding VStack, showing the UIKit view honoring SwiftUI's layout system.

Try it — Change UIActivityIndicatorView(style: .large) to .medium and watch the wrapped UIKit spinner shrink inside its SwiftUI frame.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

UIViewRepresentable.swift
struct UIViewRepresentableDemo: View {
    struct SpinnerView: UIViewRepresentable {
        func makeUIView(context: Context) -> UIActivityIndicatorView {
            let view = UIActivityIndicatorView(style: .large)
            view.startAnimating()
            view.color = .systemBlue
            return view
        }
        func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {}
    }

    var body: some View {
        VStack(spacing: 16) {
            Text("Wrapped UIKit View")
                .font(.headline)
            SpinnerView()
                .frame(width: 80, height: 80)
            Text("UIActivityIndicatorView")
                .font(.caption)
                .foregroundStyle(.secondary)
        }
        .padding()
    }
}
Live preview
Wrapped UIKit View UIActivityIndicatorView
Wrapped UIKit View UIActivityIndicatorView
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →