Home > database >  allow changing zoom of MapKit map, but from a Picker()
allow changing zoom of MapKit map, but from a Picker()

Time:10-04

ive got a screen with a map as a background, ive disabled zooming by doing UserInteraction: .pan. But i need to allow people to select the zoom level of their map by selecting a value from a picker.

Ive got the code for the picker and map done but I need to find a way to update the map when the zoom level is updated.

Basicly im just wondering how to programmicly change the zoom level of a MapKit map.

The map code:

Map(coordinateRegion: $viewModel.region,
                    interactionModes: .pan,
                    showsUserLocation: showsUser,
                    userTrackingMode: $tracking,
                    annotationItems: MapLocations,
                    annotationContent: { location in
                    MapAnnotation(
                        coordinate: location.coordinate,
                        content: {
                            ZStack{
                                Circle()
                                    .fill(.blue)
                                    .opacity(0.2)
                                    .frame(width: CGFloat(setWidth), height: CGFloat(setHeight))
                                    .overlay(
                                        RoundedRectangle(cornerRadius: CGFloat(radius))
                                            .stroke(Color.white, lineWidth: 5)
                                    )
                                    .animation(.default)
                                Circle()
                                    .fill(.red)
                                    .opacity(0.4)
                                    .frame(width: CGFloat(nextWidth), height: CGFloat(nextWidth))
                                    .overlay(
                                        RoundedRectangle(cornerRadius: CGFloat(radius))
                                            .stroke(Color.white, lineWidth: 2)
                                    )
                                    .animation(.default)
                            }
                            
                        }
                    )
                }

$viewModel. code (separate file):

final class MapViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
    static let zoomLevel: Double = (UserDefaults.standard.double(forKey: "zoomLevel"))
    static let startingLocation = CLLocationCoordinate2D(latitude: 37.33, longitude: -0-121.89)
    static let defualtSpan = MKCoordinateSpan(latitudeDelta: zoomLevel, longitudeDelta: zoomLevel)
    @Published var region = MKCoordinateRegion(center: startingLocation, span: defualtSpan)
    var locationManager: CLLocationManager?

    
    func checkIfLocationServicesIsEnabled() {
        if CLLocationManager.locationServicesEnabled() {
            locationManager = CLLocationManager()
            locationManager!.delegate = self
            locationManager?.desiredAccuracy = kCLLocationAccuracyBest
        }else{
            print("Location is not enabled, please enable")
        }
    }
    
    private func checkLocationAuthorization() {
        guard let locationManager = locationManager else { return }
        
        switch locationManager.authorizationStatus{
            
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted:
            print("your location is restricted likely due to parental controls")
        case .denied:
            print("You have denied this app to use your location, please change it in settings.")
        case .authorizedAlways, .authorizedWhenInUse:
            region = MKCoordinateRegion(center: locationManager.location!.coordinate, span:  MapViewModel.defualtSpan)
        @unknown default:
            break
        }
    }

    
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        checkLocationAuthorization()
    }
    
}

Picker code(same file as first one):

Picker("title2", selection: $selectedZoom) {
                        ForEach(zoomLevels, id: \.self) { zoomLevel in
                            Text(zoomLevel)
                        }}
                    .pickerStyle(.segmented)
                    .frame(width: 300)
                    .onChange(of: selectedZoom) { _ in
                        if selectedZoom == "0.01"{
                            UserDefaults.standard.set(0.01, forKey: "zoomLevel")
                            UserDefaults.standard.set("0.01", forKey: "zoomName")
                            UserDefaults.standard.set("0.01 (Normal)", forKey: "zoomDesc")
                            zoomDescription = "0.01 (Normal)"
                            print("1")
                        }
                        if selectedZoom == "0.02"{
                            UserDefaults.standard.set(0.02, forKey: "zoomLevel")
                            UserDefaults.standard.set("0.02", forKey: "zoomName")
                            UserDefaults.standard.set("0.02 (Zoomed)", forKey: "zoomDesc")
                            zoomDescription = "0.02 (Zoomed)"
                            print("2")
                        }
                        if selectedZoom == "0.03"{
                            UserDefaults.standard.set(0.03, forKey: "zoomLevel")
                            UserDefaults.standard.set("0.03", forKey: "zoomName")
                            UserDefaults.standard.set("0.03 (Really Zoomed)", forKey: "zoomDesc")
                            zoomDescription = "0.03 (Really Zoomed)"
                            print("3")
                        }
                        if selectedZoom == "0.04"{
                            UserDefaults.standard.set(0.04, forKey: "zoomLevel")
                            UserDefaults.standard.set("0.04", forKey: "zoomName")
                            UserDefaults.standard.set("0.04 (Normal)", forKey: "zoomDesc")
                            zoomDescription = "0.04 (Normal)"
                            print("4")
                        }
                        if selectedZoom == "0.05"{
                            UserDefaults.standard.set(0.05, forKey: "zoomLevel")
                            UserDefaults.standard.set("0.05", forKey: "zoomName")
                            UserDefaults.standard.set("0.05 (SUper zoom)", forKey: "zoomDesc")
                            zoomDescription = "0.05 (SUper zoom)"
                            print("5")
                        }
                    }

Let me know if you need anything else, thanks!

CodePudding user response:

Here is a very simple example of what you could possible do

import SwiftUI
import MapKit

struct ContentView: View {

    @StateObject var viewModel = ViewModel()

    var body: some View {
        VStack {
            Map(coordinateRegion: $viewModel.region)
            Picker("Zoom", selection: $viewModel.selectedZoom) {
                ForEach(viewModel.zoomLevels, id: \.self) { zoomLevel in
                    Text("\(zoomLevel)")
                }}
            .pickerStyle(.segmented)
            .frame(width: 300)
        }
        .padding()
    }
}

class ViewModel: ObservableObject {
    @Published var region: MKCoordinateRegion = .init(center: .init(latitude: 51.5072, longitude: 0.1276), latitudinalMeters: 500, longitudinalMeters: 500)
    @Published var selectedZoom: Int = 1 {
        didSet {
            updateRegion(for: selectedZoom)
        }
    }

    let zoomLevels = [1, 2, 3, 4, 5]

    private func updateRegion(for zoom: Int) {
        let center = region.center
        let distance = getMeters(for: zoom)
        region = MKCoordinateRegion(center: center, latitudinalMeters: distance, longitudinalMeters: distance)
    }

    private func getMeters(for zoom: Int) -> CLLocationDistance {
        500 / Double(zoom)
    }
}

CodePudding user response:

You code is a bit too confusing to understand but i made a simple example where a stepper is used to update the zoom value of the map.

struct MaptestVIew: View {
    @State var region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 0, longitude: 0), span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10))
    @State var zoomScale : Double = 1
    let baseZoom : Double = 10
    
    var body: some View {
        VStack{
            Map(coordinateRegion: $region, interactionModes: .pan)
        Stepper(value: $zoomScale, in: 1...10) {
            Text("Zoom")
        }.onChange(of: zoomScale){ newZoom in
            
            region = MKCoordinateRegion(center: region.center, span: MKCoordinateSpan(latitudeDelta: newZoom * baseZoom, longitudeDelta: newZoom * baseZoom))
        }
        }
    }
}

When the stepper changes value the span for the map region is updated. You would probably want to update your MKCoordinateRegion span to make is zoom in/out

  • Related