MapKit in SwiftUI

How to use MKMapViewDelegate methods with SwiftUI?

Anand Nimje
5 min readOct 20, 2019

Most of the iOS developers know SwiftUI is similar to the UIKit but still, there are some differences in the development phase. To learn more, let’s create MKMapView inside SwiftUI.

Let’s start with it.

If you are new with the SwiftUI then you need to check my previous blog for getting started with the SwiftUI. Now coming to the point. Create your new class with the SwiftUI.

Go to > XCode > File > New > File > SwiftUI View > Next > Name for the File

Create SwiftUI View
  • Now open your file -
import SwiftUIstruct MapView: View {
var body: some View {
Text("Hello World!")
}
}

In this class, we don’t require View protocol in place we are going to use UIViewRepresentable protocol for UIKit support inside the SwiftUI because we don’t have MapKit.

Now the question about what is the UIViewRepresentable why not View?

Press + Click

XCode Quick Help

After looking into we are getting the summary -“A view that represents a UIKit view.”

UIViewRepresentable Protocol

After replacing View Protocol with UIViewRepresentable The protocol we have to remove a body from your MapView class.

var body: some View {
Text("Hello World!")
}

You will get the warning ⚠️ for the confirm UIViewRepresentable protocol.

import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
/**
- Description - Replace the body with a make UIView(context:) method that creates and return an empty MKMapView
*/
func makeUIView(context: Context) -> MKMapView{
MKMapView(frame: .zero)
}
}

Adding one more function inside MapView class for the updates presented view

func updateUIView(_ view: MKMapView, context: Context){
let coordinate = CLLocationCoordinate2D(
latitude: 12.9716, longitude: 77.5946)
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
}
MapView

Adding the Pinpoint (Annotation) now inside the Map.

Creating now MKAnnotation model -

class LandmarkAnnotation: NSObject, MKAnnotation {
let title: String?
let subtitle: String?
let coordinate: CLLocationCoordinate2D
init(title: String?,
subtitle: String?,
coordinate: CLLocationCoordinate2D) {
self.title = title
self.subtitle = subtitle
self.coordinate = coordinate
}
}

Adding inside our MapView class-

struct MapView: UIViewRepresentable {
//Model with test data
let landmarks = LandmarkAnnotation.requestMockData()

/**
- Description - Replace the body with a make UIView(context:) method that creates and return an empty MKMapView
*/
func makeUIView(context: Context) -> MKMapView{
MKMapView(frame: .zero)
}

func updateUIView(_ view: MKMapView, context: Context){
//If you changing the Map Annotation then you have to remove old Annotations
//mapView.removeAnnotations(mapView.annotations)
//passing model array here
view.addAnnotations(landmarks)
}
}
MapView with Annotations

Now changing the image for the MKAnnotation.

Accessing the Protocol delegate methods inside the SwiftUI required Coordinator. You can write it inside your class or out of the class.

class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapViewController: MapView

init(_ control: MapView) {
self.mapViewController = control
}

func mapView(_ mapView: MKMapView, viewFor
annotation: MKAnnotation) -> MKAnnotationView?{
//Custom View for Annotation
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customView")
annotationView.canShowCallout = true
//Your custom image icon
annotationView.image = UIImage(named: "locationPin")
return annotationView
}
}

Adding this Coordinator inside MapView class.

func makeCoordinator() -> MapViewCoordinator{
MapViewCoordinator(self)
}

Once more change required for the delegate -

func updateUIView(_ view: MKMapView, context: Context){
//If you changing the Map Annotation then you have to remove old Annotations
//mapView.removeAnnotations(mapView.annotations)
//assigning delegate
view.delegate = context.coordinator
//passing model array here
view.addAnnotations(landmarks)
}

Final output of this code-

MapView with Custom Annotations

You can add any kind of image as an annotation and after clicking on this you will see the Title and subtitle inside the custom view.

Details for the Custom view

Conclusion

In this part, you came to know how to create an intermediate map view to custom. This is a pretty interesting 🧐 building MapView with the SwiftUI. It’s completely programmatically layout design. Just in few lines of code, you can make decent Design.

UIViewRepresentable the protocol is a very important part of this article you came to know now how to add UIKit inside the SwiftUI.

Coordinator was the key 🔑 point inside the for adding Delegates methods inside your class and you can give any name to this just like a normal class with the Protocols whose methods you wanted to confirm inside your class.

This is a basic example of the MapKit inside the SwiftUI you can add inside your applications view with custom height and width. I have not removed pinpoints from the map view but I have added the code inside the example if you wanted to remove it you can clean older and add new. It was the hardcoded data so not required for me but in realtime applications, It’s required. You can add UIKit the inside SwiftUI with the help of UIViewRepresentable protocol. I hope you like it. 😊✌🏼

Checkout Github repo for the final code here. 🚀

Framework Integration Interfacing with UIKit.
Source- Apple SwiftUI tutorial

Thanks for reading 🙌🏼

If you having any queries regarding this tutorial? | If you think you can do more simple way or little bit more extra things with this stuff please let me know questions, feedback or comments -on Twitter

--

--