I am trying to achieve a similar functionality to Google Maps.
When my user clicks on an existing marker, a sheet pops up showing them a page with the details of the marker.
However, if they click on the map (preferrably a long click) they should be able to add a new marker, and a sheet will pop up allowing them to enter the details of the new marker.
Here is what I have so far. I am close, but using onTapGesture is not ideal because it makes it difficult to tap on existing markers.
Also, it does not display the ‘AddNewMarkerView’ when I try adding a new marker.
I have a custom object called ‘Custom Marker’
struct CustomMarker: Identifiable, Hashable {
var id: String
var title: String
var location: CLLocationCoordinate2D
var category: String
var notes: String
// Implementing the hashValue property
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(title)
hasher.combine(location.latitude)
hasher.combine(location.longitude)
hasher.combine(category)
hasher.combine(notes)
}
// Implementing the == operator for Equatable conformance
static func ==(lhs: CustomMarker, rhs: CustomMarker) -> Bool {
return lhs.id == rhs.id &&
lhs.title == rhs.title &&
lhs.location.latitude == rhs.location.latitude &&
lhs.location.longitude == rhs.location.longitude &&
lhs.category == rhs.category &&
lhs.notes == rhs.notes
}
}
Then I have an array of markers as such:
@State private var markers: [CustomMarker] = [CustomMarker(id: "1", title: "First Marker", location: CLLocationCoordinate2D(latitude: 35.6764, longitude: 139.6500), category: "My Category", notes: "My Notes")]
I have an enum that checks which view to show in the sheet. ‘details’ if they click on an existing marker, and ‘newMarker’ if they clicked on a new location on the map and want to add a new marker.
enum ViewState {
case details
case newMarker
}
@State private var viewState: ViewState = .details
and I store the selectedMarker in this variable:
@State private var selectedMarker: CustomMarker?
and my sheet variable as such:
@State private var showingSheet: Bool = false
Finally, here is what I have in my content view to display my map and my sheet.
MapReader { proxy in
Map(selection: self.selectedMarker) {
// SHOW USER LOCATION
UserAnnotation()
// DISPLAY ALL USER'S MARKERS
ForEach(self.markers) { marker in
if self.viewState == .newMarker {
Marker(marker.title, coordinate: marker.location)
} else {
Marker(marker.title, coordinate: marker.location)
.tag(marker)
}
}
}
.onTapGesture { position in
self.viewState = .newMarker
if let coordinate = proxy.convert(position, from: .local) {
let newMarker = CustomMarker(
id: "",
title: "",
location: CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude),
category: "",
notes: ""
)
self.markers.append(newMarker)
self.selectedMarker = newMarker
}
}
}
.sheet(isPresented: self.$showingSheet, onDismiss: {
self.markers.removeLast()
}, content: {
switch self.viewState {
case .details:
MarkerDetailsView()
case .newMarker:
AddNewMarkerView()
}
})
.onChange(of: self.selectedMarker, { oldValue, newValue in
if newValue != nil {
self.viewState = .details
self.showingSheet = true
} else {
self.showingSheet = false
}
})
Any help is appreciated, thank you very much in advance 🙂