Is there a way to update the MKCoordinateRegion of a MapView sheet/NavigationLink on appear?
I have a view that is being used to input some data to create a longitude/latitude combination from a street address:
Create.swift:
@State var longitude:Double = -122.677579; // Default longitude
@State var latitude:Double = 45.515519; // Default latitude
@State var streetAddress:String = ""; // Empty string
@State private var isShowing = false;
var body:some View {
VStack {
/* Take in the street address string via TextField */
Button(action:{validate()}, label:"Next")
}
.sheet(isPresented:$isShowing) {
LocationPicker(longitude:self.longitude, latitude:self.latitude)
};
}
func validate() {
var isValid:Bool = false;
/*
1. convert the street address to longitude and latitude
2. store long/lat in self.longitude, self.latitude
3. set isValid to true
*/
isShowing = true;
}
The flow:
- Accept a street address from the user
- clicking the 'next' button validates the street address by converting it to longitude/latitude
- Those longitude and latitude values are stored in the state variables
- isShowing is set to true, bringing up the
.sheet
, which contains aLocationPicker
view.
LocationPicker.swift:
struct LocationPicker: View {
@State var latitude:Double;
@State var longitude:Double;
var span:MKCoordinateSpan = MKCoordinateSpan(
latitudeDelta: 0.009,
longitudeDelta: 0.009
)
@State var region:MKCoordinateRegion;
init(latitude:Double, longitude:Double) {
_latitude = State(initialValue: latitude)
_longitude = State(initialValue: longitude)
_region = State(initialValue :MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
span: self.span
))
}
var body:some View {
Map(coordinateRegion: $region,
showsUserLocation: false
)
/* ... */
}
}
The issue I have with this configuration is that the .sheet
's LocationPicker
in Create.swift
gets rendered when the Create.swift
view gets rendered. So when I pass the longitude/latitude states into the sheet's LocationPicker
, the default values are passed, and the centerpoint that appears when the map opens is the default coordinates rather than the coordinates that are generated by the streetAddress
in validate()
.
I've attempted to use both an invisible NavigationLink
and a .sheet
in Create.swift
, but both render at the same time as the parent. I tried using @Binding
doubles for LocationPicker.swift
:
struct LocationPicker: View {
@Binding var latitude:Double;
@Binding var longitude:Double;
var span:MKCoordinateSpan = MKCoordinateSpan(
latitudeDelta: 0.009,
longitudeDelta: 0.009
)
@State var region:MKCoordinateRegion;
init(latitude:Binding<Double>, longitude:Binding<Double>) {
_latitude = latitude
_longitude = longitude
_region = State(initialValue :MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
span: self.span
))
}
var body:some View {
Map(coordinateRegion: $region,
showsUserLocation: false
)
/* ... */
}
However, CLLocationCoordinate2D
does not accept Binding<Double>
as a data type for latitude or longitude.
CodePudding user response:
When you pass a Binding
in to an init, if you need to use the values contained in the Binding
, you must use .wrappedValue
to access the underlying values. In this case, you are passing in two Binding<Double>
and are attempting to use them to create a CLLocationCoordinate2D
, so the initializer would have to look like this:
init(latitude:Binding<Double>, longitude:Binding<Double>) {
// Binding
_latitude = latitude
// Binding
_longitude = longitude
_region = State(initialValue :MKCoordinateRegion(
// not Bindings
center: CLLocationCoordinate2D(latitude: latitude.wrappedValue, longitude: longitude.wrappedValue),
span: self.span
))
}