UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

MKMapView and Delegate

Forums > SwiftUI

Hello

I understand that to use MKMapView and need to use it's delegeate MKMapViewDelegate.

The example below does this (also CLLocationManagerDelegate) and I can embed a view and it works fine.

MKMapView has a bunch of properties such as showCompass, showBuildings, pointOfInterestFilter etc. I can set these in the delegate ok.

My question is how do I access these from my interface?

Regards

import SwiftUI
import CoreLocation
import MapKit

struct ContentView: View {

    @StateObject var locationViewModel = LocationViewModel()
    var parent = MapView()

    var body: some View {
        VStack {
            MapView()
                .ignoresSafeArea()
                .overlay {

                    Button(action: {
                        parent.testFunc()
                    }) {
                        VStack {
                            Spacer()
                            HStack {
                                Spacer()
                                ZStack {
                                    RoundedRectangle(cornerRadius: 5)
                                        .frame(width: 40, height: 40)
                                        .foregroundColor(.white)

                                    Image(systemName: "map.fill")
                                        .font(.system(size: 30))
                                        .foregroundColor(.gray)

                                }
                                .padding(.trailing, 10)
                            }
                            Spacer()
                        }
                    }
                }
        }
        .onAppear {
            if locationViewModel.authorizationStatus == .notDetermined {
                locationViewModel.requestPermission()
            }
        }
    }
}

struct MapView: UIViewRepresentable {

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

    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView

        init(_ parent: MapView) {
            self.parent = parent
        }

        func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
            //print(mapView.centerCoordinate)
        }

        func mapView(_ mapView: MKMapView,
                     didUpdate userLocation: MKUserLocation) {
            print("User location\(userLocation.coordinate)")
        }

        func mapViewWillStartLoadingMap(_ mapView: MKMapView) {
            print("Map will start loading")
        }

        func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
            print("Map did finish loading")
        }

        func mapViewWillStartLocatingUser(_ mapView: MKMapView) {
            print("Map will start locating user")
        }

        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)
            view.canShowCallout = true
            return view
        }
    }

    func makeUIView(context: Context) -> MKMapView {

        let region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: -37.8136, longitude: 144.9631), span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))

        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        mapView.region = region

        mapView.showsScale = true
        mapView.setUserTrackingMode(MKUserTrackingMode.followWithHeading, animated: true)
        mapView.userTrackingMode = MKUserTrackingMode.followWithHeading

        mapView.showsUserLocation = true
        //mapView.showsCompass = false

        return mapView
    }

    func updateUIView(_ view: MKMapView, context: Context) {
    }

    func testFunc()  {
        print("Toggle Compass")
    }
}

class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
    @Published var authorizationStatus: CLAuthorizationStatus

    private let locationManager: CLLocationManager

    override init() {
        locationManager = CLLocationManager()
        authorizationStatus = locationManager.authorizationStatus

        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
    }

    func requestPermission() {
        locationManager.requestWhenInUseAuthorization()
    }

    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        authorizationStatus = manager.authorizationStatus
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3      

Give your MapView some @Binding properties for the stuff you want to change, annd then set up an @State in your parent View to hold the current value.

So, for instance:

//in ContentView

@State private var mapType: MKMapType = .standard
//when you create the MapView
MapView(mapType: $mapType)

//and add a Button to change mapType
//in MapView
@Binding var mapType: MKMapType

func updateUIView(_ view: MKMapView, context: Context) {
    view.mapType = mapType
}

3      

Hello

Many thanks for that. I did a quick experiment to turn on and off the compass and step through map type and works a treat.

I am curious about how the centerCoordinate property v's the setCenter func works.

Regards

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.