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