Some MapKit questions in SwiftUI

Viewed 14

I'm looking to make a setting view in my app where I could define 3 map parameters :

  • Map center initial position
  • Map initial zoom
  • Map initial type

Then show an example map and save in into the @AppStorage

My initial position is determined from an array of data which include :

  • Place name
  • Place Latitude
  • Place Longitude

Latitude and Longitude is find via a function which return a Double? :

func getApLat(ApName: String) -> Double?{
        
            guard let foundAirport = FR_airportsDB.first(where: {$0.Icao == ApName}),
                      let lat = Double(foundAirport.Latitude) else { return nil }
                
                return lat
        }
        
func getApLong(ApName: String) -> Double?{
        
            guard let foundAirport = FR_airportsDB.first(where: {$0.Icao == ApName}),
                      let longit = Double(foundAirport.Longitude) else { return nil }
                
                return longit
    
}

Now my settingMapView is defined as follow :

struct MapOptionView: View {
    
    @State private var showingAlert = false
    @State private var latDouble = getApLat(ApName: UserDefaults.standard.string(forKey: "MAP_CenterInit") ?? "LFLI")
    @State private var longDouble = getApLong(ApName: UserDefaults.standard.string(forKey: "MAP_CenterInit") ?? "LFLI")
    @State private var typeExemple: MKMapType = getTypeFromUD()
    @State private var exampleZoom: Int = 5
    
    @AppStorage("MAP_CenterInit") private var MapCenterAirport = ""
    @AppStorage("MAP_ZoomInit") private var MapZoom = 2
    @AppStorage("MAP_TypeInit") private var MapType = 1

    
    var body: some View {
        List{
            Section(header: Text("Initial location")){
                HStack{
                    TextField("ICAO", text: $MapCenterAirport)
                        .padding()
                        .background(.white)
                        .cornerRadius(20.0)
                        .keyboardType(.default)
                        .textCase(.uppercase)
                        .onReceive(Just(MapCenterAirport)) { inputValue in
                                    if inputValue.count > 4 {
                                        self.MapCenterAirport.removeLast()
                                    }
                        }
                        .disableAutocorrection(true)
                        .textCase(.uppercase)
                    if MapCenterAirport != "" {
                        Button {

//Here I update the center data after get it from the function 

                            latDouble = getApLat(ApName: MapCenterAirport) 
                            longDouble = getApLong(ApName: MapCenterAirport) 
                        } label: {
                            Text("Check")
                        }
                    }

                }
            }

// Section where Zoom is defined

            Section(header: Text("Initial zoom")){
                HStack {
                    if MapZoom == 1{
                        Text("Zoom : Low")
                    }else if MapZoom == 2{
                        Text("Zoom : Medium")
                    }else if MapZoom == 3{
                        Text("Zoom : Large")
                    }
                    Spacer()
                    Stepper("", value: $MapZoom, in: 1...3)
                }.padding(.vertical)
            }

// Section where Type is defined

            Section(header: Text("Initial type")){
                HStack {
                    if MapType == 1{
                        Text("Type : Standard")
                    }else if MapType == 2{
                        Text("Type : Satellite")
                    }else if MapType == 3{
                        Text("Type : Satellite-flyover")
                    }else if MapType == 4{
                        Text("Type : Hybrid")
                    }else if MapType == 5{
                        Text("Type : Hybrid-flyover")
                    }
                    Spacer()
                    Stepper("", value: $MapType, in: 1...5)
                        .frame(width: 60)
                        .padding(.horizontal, 20)
                }.padding(.vertical)
            }

// Section where Exemple is Show but need to clickButton to update map ...

            Section(header: Text("Example")){
                Button {
//Here is zoom adaptation regarding stepper choice from $MapZoom
                    if MapZoom == 1{
                        exampleZoom = 60000
                    }else if MapZoom == 2{
                        exampleZoom = 110000
                    }else if MapZoom == 3{
                        exampleZoom = 160000
                    }
//Here is type adaptation regarding stepper choice from $MapType
                    if MapType == 1{
                        typeExemple = .standard
                    }else if MapType == 2{
                        typeExemple = .satellite
                    }else if MapType == 3{
                        typeExemple = .satelliteFlyover
                    }else if MapType == 4{
                        typeExemple = .hybrid
                    }else if MapType == 5{
                        typeExemple = .hybridFlyover
                    }
                    
                    
                } label: {
                    HStack {
                        Text("Update example")
                    }
                }

//Here is my Map definition 

                MapViewSetting(mapType: $typeExemple,
                               funcLat: $latDouble,
                               funcLong: $longDouble,
                               funcZoom: $exampleZoom
                )
                    .edgesIgnoringSafeArea(.all)
                    .frame(height: 300)
            }
        }.navigationTitle("Map options")
            .navigationBarItems(trailing: Button(action: {
                showingAlert = true

//Here we save the 3 value into the AppStorage 

                MapCenterAirport = MapCenterAirport.uppercased()
                UserDefaults.standard.set(self.MapCenterAirport, forKey: "MAP_CenterInit")
                UserDefaults.standard.set(self.MapZoom, forKey: "MAP_ZoomInit")
                UserDefaults.standard.set(self.MapType, forKey: "MAP_TypeInit")
                
            }, label: {
                HStack {
                    Text("Save")
                }
            })).alert("Informations saved !\nMust have to restart the app to apply it.", isPresented: $showingAlert) {
                Button("OK", role: .cancel) { }
            }
    }
}

And finally I've my map struct defined as follow after following some post find on this forum.

struct MapViewSetting: UIViewRepresentable {

    @Binding var mapType: MKMapType
    @Binding var funcLat: Double
    @Binding var funcLong: Double
    @Binding var funcZoom: Int

    func makeUIView(context: Context) -> MKMapView {

        let mapView = MKMapView(frame: .zero)
        
        let center = CLLocationCoordinate2D(latitude: funcLat, longitude: funcLong)
        let region = MKCoordinateRegion(center: center,
                                        latitudinalMeters: CLLocationDistance(funcZoom),
                                        longitudinalMeters: CLLocationDistance(funcZoom)
        )
        
        mapView.setRegion(region, animated: true)

        mapView.mapType = mapType
        mapView.showsScale = true
        mapView.showsTraffic = false
        mapView.showsCompass = true
        mapView.showsUserLocation = false
        mapView.showsBuildings = false
        return mapView
    }

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

        view.mapType = self.mapType

    }
}

But Two big mistake with my code :

First I got an error here :

MapViewSetting(mapType: $typeExemple,
                               /*regionFunc: $region,*/
                            funcLat: $latDouble ?? 46.192001,
                            funcLong: $longDouble ?? 6.26839,
                               funcZoom: $exampleZoom
                )

On funcLat : and funcLong which say : Cannot convert value of type 'Binding<Double?>' to expected argument type 'Binding<Double>'

And If I define manually the Lat and Long in my code to test the two other parameters I could only change the type but not the Zoom ...

Hope to be as clear as I can

Thanks

0 Answers
Related