In the code below, I want to allow the user to later edit the properties of a selected location in a new View as a sheet view modifier attached to the Map. It's not launching when I long press a previously selected location.
import SwiftUI
import MapKit
struct ContentView: View {
@State private var userLocations = [UserLocation]()
@State private var selectedPlace: UserLocation? = nil
let startPosition = MapCameraPosition.region(
MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 42.196, longitude: 24.747),
span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10)
)
)
var body: some View {
MapReader { proxy in
Map(initialPosition: startPosition) {
ForEach(userLocations) { location in
Annotation(location.name, coordinate: location.coordinate) {
Image(systemName: "star.circle")
.resizable()
.foregroundStyle(.red)
.frame(width: 44, height: 44)
.background(.white)
.clipShape(Circle())
.onLongPressGesture {
selectedPlace = location
}
}
}
}
.onTapGesture { position in
if let coordinate = proxy.convert(position, from: .local) {
let newLocation = UserLocation(
id: UUID(),
name: "New Location",
description: "",
latitude: coordinate.latitude,
longitude: coordinate.longitude
)
userLocations.append(newLocation)
}
}
.sheet(item: $selectedPlace) { place in
Text(place.name)
}
}
}
}
Below is the location data struct in a separate Swift file
import Foundation
import MapKit
struct UserLocation: Codable, Equatable, Identifiable {
let id: UUID
var name: String
var description: String
var latitude: Double
var longitude: Double
var coordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}
I added prints in action places (onTapGesture, onLongPressGesture). The print in onTapGesture executes, and the locations do display on selection.
But no print on onLongPressGesture. Which means the LongPressGesture doesn't get triggered on Long Press. And that's beyond my understanding at the moment.
PS: SwiftUI beginner here. Thanks in advance for your help.
The map is probably recognising your long press as a drag gesture to drag the map. It takes longer for a long press to be recognised compared to a drag gesture. The minimum duration for a long press is probably longer than the minimum duration required for a drag, which in turns is longer than the minimum duration required for a tap. If I set the minimum duration for a long press to be something small, like 0.1, .onLongPressGesture(minimumDuration: 0.1)
, then the long press is triggered.
You can fix this by making it detect long presses and drags simultaneously, as opposed to forgetting about the long press as soon as the minimum duration for the drag is reached.
.simultaneousGesture(LongPressGesture().onEnded { _ in
selectedPlace = location
})