How to change map type to satellite in SwiftUI

How to change map type to satellite in SwiftUI

I’m trying to help my son learn SwiftUI. We’re going through the tutorial provided by Apple. After playing around with the basic app they have you build, he decided he wanted to set the map view to satellite mode. Is there a way to do that in SwiftUI?

This is the code he’s working with. We’re running Xcode version 11.5 on Catalina. Sorry I don’t have too much knowledge in this area

Code Block
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
    func updateUIView(_ uiView: MKMapView, context: Context) {
        let coordinate = CLLocationCoordinate2D(latitude: -2.1230, longitude: -80.0438)
        let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        uiView.setRegion(region, animated: true)
        
    }
    
}
struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
        
    }
}


Accepted Reply

If you want to hardcode the setting for Satellite you can simply add the following code in line 29 of your example

Code Block
uiView.mapType = .satellite


Replies

There are multiple ways to go about this, but I like the approach of a State variable named "action" into your SwiftUI view, and via that variable, you update the map type.

The following project has a number of examples of using UIKit stuff in your SwiftUI project. I already had a MapKit example, and have updated it to allow changing the map type:

GitHub

The code in question:
Code Block swift
import SwiftUI
import CoreLocation
import MapKit
extension CLLocationCoordinate2D {
var description: String {
String(format: "%.8f, %.8f", self.latitude, self.longitude)
}
}
extension MapKitExample {
struct PickerValues {
let mapType: MKMapType
let description: String
}
}
struct MapKitExample: View {
static let amsterdam = CLLocationCoordinate2D(latitude: 52.37403,
longitude: 4.88969)
@State private var centerCoordinate = Self.amsterdam
@State private var action: MapView.Action = .idle
@State private var mapPickerSelection: Int = 0
let pickerValues: [PickerValues] = [// [.standard, .hybrid, .satellite]
PickerValues(mapType: .standard, description: "Standard"),
PickerValues(mapType: .hybrid, description: "Hybrid"),
PickerValues(mapType: .satellite, description: "Satellite"),
]
var body: some View {
let binding = Binding<Int>(
get: { self.mapPickerSelection},
set: { newValue in
self.action = .changeType(mapType: self.pickerValues[newValue].mapType)
self.mapPickerSelection = newValue
}
)
return VStack {
MapView(centerCoordinate: self.$centerCoordinate, action: self.$action)
Picker(selection: binding, label: Text("Map type")) {
ForEach(self.pickerValues.indices) { index in
Text(self.pickerValues[index].description).tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
Text("Centered on: " + self.centerCoordinate.description)
Button("Reset") {
self.action = .reset(coordinate: Self.amsterdam)
}
}
.navigationBarTitle("MapKit Example")
}
}
struct MapView: UIViewRepresentable {
enum Action {
case idle
case reset(coordinate: CLLocationCoordinate2D)
case changeType(mapType: MKMapType)
}
@Binding var centerCoordinate: CLLocationCoordinate2D
@Binding var action: Action
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.delegate = context.coordinator
mapView.centerCoordinate = self.centerCoordinate
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
switch action {
case .idle:
break
case .reset(let newCoordinate):
uiView.delegate = nil
uiView.centerCoordinate = newCoordinate
DispatchQueue.main.async {
self.centerCoordinate = newCoordinate
self.action = .idle
uiView.delegate = context.coordinator
}
case .changeType(let mapType):
uiView.mapType = mapType
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
parent.centerCoordinate = mapView.centerCoordinate
}
init(_ parent: MapView) {
self.parent = parent
}
}
}


If you want to hardcode the setting for Satellite you can simply add the following code in line 29 of your example

Code Block
uiView.mapType = .satellite