SwiftUI에서 지원되지 않는 기능을 구현할 때, UIKit의 기능이 필요할 수 있습니다.
이 때, UIViewRepresentable 프로토콜을 채택하여 구현하면, SwiftUI에서 UIKit의 View를 사용할 수 있습니다.
참고: https://developer.apple.com/documentation/swiftui/uiviewrepresentable
import SwiftUI
import MapKit
struct MapViewRepresentable: UIViewRepresentable {
let mapView = MKMapView()
/// 사용할 UIView를 생성하고, 초기화하는 메서드
func makeUIView(context: Context) -> MKMapView {
return mapView
}
/// UIView의 뷰 업데이트가 필요할 때 호출되는 메서드
func updateUIView(_ uiView: MKMapView, context: Context) {
}
}
MapKit을 사용해서 지도를 보여주고 싶을 때, UIKit에서는 MKMapView 인스턴스를 생성해서 구현할 수 있었습니다. SwiftUI에서도 MKMapView를 사용하기 위해서는 UIViewRepresentable 프로토콜을 채택하고 구현할 필요가 있습니다.
struct MapView: View {
var body: some View {
MapViewRepresentable()
.ignoresSafeArea()
}
}
그리고 SwiftUI에서는 UIViewRepresentable을 구현한 구조체를 위와 같이 사용하면 됩니다.
Coordinator를 통해 delegate 메서드를 구현하고, 사용자의 현재 위치로 지도를 이동시키는 예제입니다.
extension MapViewRepresentable {
final class MapViewCoordinator: NSObject, MKMapViewDelegate {
private let parent: MapViewRepresentable
private let locationManager = CLLocationManager()
init(parent: MapViewRepresentable) {
self.parent = parent
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
super.init()
}
//MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
let coordinate = userLocation.coordinate
let region = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
)
parent.mapView.setRegion(region, animated: true)
}
}
}
Coordinator를 생성할 때, MapViewRepresentable을 파라미터로 받아 프로퍼티로 저장합니다. 이를 통해 mapView에 접근할 수 있습니다.
locationManager는 위치 권한을 요청하기 위해 사용합니다. 위치 권한이 없으면, delegate 메서드를 구현해도 사용자의 위치 정보를 가져올 수 없습니다.
또한, info.plist 에서 위 요소를 추가해줘야합니다.
MKMapViewDelegate를 채택하고, mapView(didUpdate:) 메서드를 구현했습니다.
이 메서드를 통해 사용자의 현재 위치를 알아낼 수 있습니다.
struct MapViewRepresentable: UIViewRepresentable {
/// 사용할 UIView를 생성하고, 초기화하는 메서드
func makeUIView(context: Context) -> MKMapView {
mapView.showsUserLocation = true
mapView.delegate = context.coordinator
return mapView
}
/// UIView의 뷰 업데이트가 필요할 때 호출되는 메서드
func updateUIView(_ uiView: MKMapView, context: Context) { }
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(parent: self)
}
}
UIViewRepresentable에서는 makeCoordinator() 메서드를 통해 Coordinator 인스턴스를 생성해 리턴하고, makeUIView(context:) 메서드에서 delegate를 설정합니다.