UIKit Interoperability
UIViewRepresentable
Use for: Wrapping UIKit views in SwiftUI
struct WebView: UIViewRepresentable {
let url: URL
@Binding var isLoading: Bool
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
let request = URLRequest(url: url)
webView.load(request)
}
func makeCoordinator() -> Coordinator {
Coordinator(isLoading: $isLoading)
}
class Coordinator: NSObject, WKNavigationDelegate {
@Binding var isLoading: Bool
init(isLoading: Binding<Bool>) {
_isLoading = isLoading
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
isLoading = true
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
isLoading = false
}
}
}
// Usage
struct ArticleWebView: View {
let url: URL
@State private var isLoading = false
var body: some View {
WebView(url: url, isLoading: $isLoading)
.overlay {
if isLoading {
ProgressView()
}
}
}
}UIViewControllerRepresentable
Use for: Presenting UIKit view controllers
struct ImagePicker: UIViewControllerRepresentable {
@Binding var image: UIImage?
@Environment(\.dismiss) private var dismiss
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.filter = .images
config.selectionLimit = 1
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
// No updates needed
}
func makeCoordinator() -> Coordinator {
Coordinator(image: $image, dismiss: dismiss)
}
class Coordinator: NSObject, PHPickerViewControllerDelegate {
@Binding var image: UIImage?
let dismiss: DismissAction
init(image: Binding<UIImage?>, dismiss: DismissAction) {
_image = image
self.dismiss = dismiss
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss()
guard let provider = results.first?.itemProvider else { return }
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { image, _ in
DispatchQueue.main.async {
self.image = image as? UIImage
}
}
}
}
}
}
// Usage
struct ProfileEditView: View {
@State private var profileImage: UIImage?
@State private var showImagePicker = false
var body: some View {
VStack {
if let image = profileImage {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.clipShape(Circle())
}
Button("Choose Photo") {
showImagePicker = true
}
}
.sheet(isPresented: $showImagePicker) {
ImagePicker(image: $profileImage)
}
}
}