MapKit in SwiftUI

How to use MKMapViewDelegate methods with SwiftUI?

Anand Nimje
Oct 20, 2019 · 5 min read
Image for post
Image for post

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.

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

Image for post
Image for post
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?

Image for post
Image for post
XCode Quick Help

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

Image for post
Image for post
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)
}
Image for post
Image for post
MapView

Adding the Pinpoint (Annotation) now inside the Map.

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)
}
}
Image for post
Image for post
MapView with Annotations

Now changing the image for the MKAnnotation.

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-

Image for post
Image for post
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.

Image for post
Image for post
Details for the Custom view

Conclusion

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 🙌🏼

Flawless iOS

🍏 Community around iOS development, mobile design, and…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store