SwiftUI – MapKit

By | 08/11/2023

In this post, we will see a brief introduction to MapKit and how we can use it in our applications.
But first of all, what is MapKit?
From Apple web site:
MapKit for SwiftUI allows you to build map-centric views and apps across Apple platforms. You can design expressive and highly interactive Maps with minimal code by composing views, using ViewBuilders and view modifiers.
Like MapKit for AppKit and UIKit, MapKit for SwiftUI allows you to take advantage of map styles ranging from satellite imagery to rich, 3D perspective imagery to present vivid maps.


Starting to create a new application with Xcode and let’s see some examples:

CREATING A MAP:

[contentview.swift]

import SwiftUI
struct ContentView: View {
    @State private var showMap = false
        var body: some View {
            ZStack {
                // Background color
                Color.blue
                    .edgesIgnoringSafeArea(.all)
                
                VStack {
                    Text("Explore the Map!")
                        .font(.largeTitle)
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .shadow(radius: 3)
                    
                    Spacer().frame(height: 20) // Provide a bit of spacing
                    
                    Button(action: {
                        withAnimation {
                            showMap.toggle()
                        }
                    }) {
                        Text("Show Map")
                            .font(.headline)
                            .foregroundColor(.white)
                            .padding(.horizontal, 40)
                            .padding(.vertical, 12)
                            .background(Color.green)
                            .cornerRadius(10)
                            .shadow(radius: 3)
                    }
                    
                    // Conditionally display the MapView based on the state of `showMap`
                    if showMap {
                        ViewMap()
                            .transition(.move(edge: .bottom)) // Use a bottom-to-top transition for the map
                            .edgesIgnoringSafeArea(.all)
                    }
                }
            }
        }
    }
#Preview {
    ContentView()
}


[viewmap.swift]

import SwiftUI
import MapKit

struct ViewMap: View {
    var body: some View {
        Map()
    }
}

#Preview {
    ViewMap()
}


MAP STYLE:
We can choose three map styles:
Standard: street map with road
Imagery: Satellite image
Hybrid: Standard and Imagery

[viewmap.swift]

import SwiftUI
import MapKit

struct ViewMap: View {
        var body: some View {
            Map()
                .mapStyle(.hybrid(elevation: .realistic))
        }
}

#Preview {
    ViewMap()
}


MARKERS
:
Markers are an useful feature in MapKit that allow us to display content at a specific coordinate on the map:

[viewmap.swift]

import SwiftUI
import MapKit

struct ViewMap: View {
    private var labelPosition = "Colosseum position for test"
        var body: some View {
            Map(){
                Marker(labelPosition, coordinate: .romeColosseum)
            }
        }
}

#Preview {
    ViewMap()
}

extension CLLocationCoordinate2D {
    static let romeColosseum = CLLocationCoordinate2D(latitude: 41.890210, longitude: 12.492231)
}


Obviously, if we define two ore more markers, they will be shown on the map at the same time:

import SwiftUI
import MapKit

struct ViewMap: View {
    private var labelPosition = "Colosseo"
    private var labelPosition2 = "San Pietro"
    private var labelPosition3 = "Piazza di Sspagna"
        var body: some View {
            Map(){
                Marker(labelPosition, coordinate: .romeColosseum)
                Marker(labelPosition2, coordinate: .sanPietro)
                Marker(labelPosition3, coordinate: .piazzaDiSpagna)
            }
        }
}

#Preview {
    ViewMap()
}

extension CLLocationCoordinate2D {
    static let romeColosseum = CLLocationCoordinate2D(latitude: 41.890210, longitude: 12.492231)
    static let sanPietro = CLLocationCoordinate2D(latitude: 41.90250201050693, longitude: 12.457254010082337)
    static let piazzaDiSpagna = CLLocationCoordinate2D(latitude: 41.90585109305216, longitude: 12.482358262120242)
}


ANNOTATIONS:
Annotations are very similar to Markers but, they can be customized more easly:

import SwiftUI
import MapKit

struct ViewMap: View {
    private var labelPosition = "Colosseo position for test"
    private var labelPosition2 = "San Pietro"
    private var labelPosition3 = "Piazza di Spagna"
        var body: some View {
            Map(){
                
                Annotation("San Pietro", coordinate: .sanPietro, anchor: .bottom) {
                    ZStack {
                        Circle()
                            .foregroundStyle(.yellow)
                            .frame(width: 40, height: 40)
                 
                        Image(systemName: "car.circle")
                            .padding()
                            .foregroundStyle(.black)
                            .clipShape(Circle())
                    }
                }
                
                Annotation("Colosseo", coordinate: .romeColosseum, anchor: .bottom) {
                    ZStack {
                        Circle()
                            .foregroundStyle(.blue)
                            .frame(width: 40, height: 40)
                 
                        Image(systemName: "car.circle")
                            .padding()
                            .foregroundStyle(.yellow)
                            .clipShape(Circle())
                    }
                }
                
                Annotation("Piazza di Spagna", coordinate: .piazzaDiSpagna, anchor: .bottom) {
                    ZStack {
                        Circle()
                            .foregroundStyle(.black)
                            .frame(width: 40, height: 40)
                 
                        Image(systemName: "car.circle")
                            .padding()
                            .foregroundStyle(.white)
                            .clipShape(Circle())
                    }
                }
                
            }
        }
}

#Preview {
    ViewMap()
}

extension CLLocationCoordinate2D {
    static let romeColosseum = CLLocationCoordinate2D(latitude: 41.890210, longitude: 12.492231)
    static let sanPietro = CLLocationCoordinate2D(latitude: 41.90250201050693, longitude: 12.457254010082337)
    static let piazzaDiSpagna = CLLocationCoordinate2D(latitude: 41.90585109305216, longitude: 12.482358262120242)
}


CHANGING OF MAP’S POSITION:

import SwiftUI
import MapKit

struct ViewMap: View {
    // definition of MapCameraPosition that describes
    // how to position the map’s camera within the map.
    @State private var position: MapCameraPosition = .automatic
        var body: some View {
            Map(position: $position)
                       // when the Map is loaded, the application
                       // will show 'San Pietro'
                       .onAppear {
                           position = .item(MKMapItem(placemark: .init(coordinate: .sanPietro)))
                       }
                        // in the Safe Area, wwe will two buttons
                       .safeAreaInset(edge: .bottom) {
                           HStack {
                               // button used to move the map towards 'Piazza di Spagna'
                               Button(action: {
                                   withAnimation {
                                       position = .item(MKMapItem(placemark: .init(coordinate: .piazzaDiSpagna)))
                                   }
                               }) {
                                   Text("Piazza di Spagna")
                               }
                               .tint(.black)
                               .buttonStyle(.borderedProminent)
                               .padding()
                               
                               // button used to move the map towards 'Colosseo'
                               Button(action: {
                                   withAnimation {
                                       position = .item(MKMapItem(placemark: .init(coordinate: .romeColosseum)))
                                   }
                               }) {
                                   Text("Colosseo")
                               }
                               .tint(.black)
                               .buttonStyle(.borderedProminent)
                               .padding()
                           }
                           .frame(width: 400, height: 100)
                           .background(.white)
                       }
        }
}

#Preview {
    ViewMap()
}

extension CLLocationCoordinate2D {
    static let romeColosseum = CLLocationCoordinate2D(latitude: 41.890210, longitude: 12.492231)
    static let piazzaDiSpagna = CLLocationCoordinate2D(latitude: 41.90585109305216, longitude: 12.482358262120242)
    static let sanPietro = CLLocationCoordinate2D(latitude: 41.90250201050693, longitude: 12.457254010082337)
}



Leave a Reply

Your email address will not be published. Required fields are marked *