我在 SwiftUI 应用程序中有一张地图。它已经发挥到一定程度了;但现在我希望能够点击它并知道点击的纬度和经度。这是当前代码:
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
@Binding var centerCoordinate: CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.delegate = context.coordinator
let gRecognizer = UITapGestureRecognizer(target: context.coordinator,
action: #selector(Coordinator.tapHandler(_:)))
mapView.addGestureRecognizer(gRecognizer)
return mapView
}
func updateUIView(_ view: MKMapView, context: Context) {
//print(#function)
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
let gRecognizer = UITapGestureRecognizer(target: self,
action: #selector(tapHandler(_:)))
@objc func tapHandler(_ gesture: UITapGestureRecognizer) {
print(#function)
.... get useful information here ...
}
}
}
在这种状态下,我可以看到我何时点击,但我没有获得我需要的信息(即点击的坐标)。 在搜索网络后,我尝试了代码的一些变体。 目前还无法正常工作。任何有关出行方式的相关提示都将非常受欢迎。
我也遇到过类似的情况,我就是这么做的。 我制作了 Coordinator UIGestureRecognizerDelegate,并确保将 gRecognizer delegate 设置为它,并将其添加到地图中。比如:
struct MapView: UIViewRepresentable {
@Binding var centerCoordinate: CLLocationCoordinate2D
let mapView = MKMapView()
func makeUIView(context: Context) -> MKMapView {
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ view: MKMapView, context: Context) {
//print(#function)
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate, UIGestureRecognizerDelegate {
var parent: MapView
var gRecognizer = UITapGestureRecognizer()
init(_ parent: MapView) {
self.parent = parent
super.init()
self.gRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapHandler))
self.gRecognizer.delegate = self
self.parent.mapView.addGestureRecognizer(gRecognizer)
}
@objc func tapHandler(_ gesture: UITapGestureRecognizer) {
// position on the screen, CGPoint
let location = gRecognizer.location(in: self.parent.mapView)
// position on the map, CLLocationCoordinate2D
let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView)
}
}
}
当我尝试为在 macOS 上运行的 SwiftUI 应用程序获取地图上的点击位置时,我遇到了类似的问题,所以显然,我必须使用
NSViewRepresentable
而不是 UIViewRepresentable
。
@workingdog 的回答很有帮助;这是我的 macOS 版本,它在
Text
视图中显示单击的位置,Z 堆叠在地图顶部:
struct MapViewRepresentable: NSViewRepresentable {
@Binding var clickedCoordinate: CLLocationCoordinate2D
var initialLocation: CLLocationCoordinate2D
var initialSpan: MKCoordinateSpan
let mapView = MKMapView()
func makeNSView(context: Context) -> MKMapView {
mapView.preferredConfiguration = MKHybridMapConfiguration(elevationStyle: .realistic)
mapView.region = MKCoordinateRegion(center: initialLocation, span: initialSpan)
mapView.delegate = context.coordinator
return mapView
}
func updateNSView(_ nsView: MKMapView, context: Context) {
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate, NSGestureRecognizerDelegate {
@State var parent: MapViewRepresentable
var gRecognizer = NSClickGestureRecognizer()
init(_ parent: MapViewRepresentable) {
self.parent = parent
super.init()
self.gRecognizer = NSClickGestureRecognizer(target: self, action: #selector(tapHandler))
self.gRecognizer.delegate = self
self.parent.mapView.addGestureRecognizer(gRecognizer)
}
@objc func tapHandler(_ gesture: NSClickGestureRecognizer) {
let location = gesture.location(in: self.parent.mapView)
let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView)
parent.clickedCoordinate = coordinate
}
}
}
struct MapView: View {
private static let initialLocation = CLLocationCoordinate2D(latitude: 51.5, longitude: 0.0) // London, UK
private static let initialSpan = MKCoordinateSpan(latitudeDelta: 1.0, longitudeDelta: 1.0)
@State private var clickedCoordinate: CLLocationCoordinate2D = Self.initialLocation
var body: some View {
ZStack {
MapViewRepresentable(clickedCoordinate: $clickedCoordinate, initialLocation: Self.initialLocation, initialSpan: Self.initialSpan)
HStack {
Spacer()
VStack(alignment: .trailing) {
Spacer()
Text("Clicked - Lat: \(latAsStr(clickedCoordinate.latitude)) Lon: \(lonAsStr(clickedCoordinate.longitude))")
.background(.white).opacity(0.75)
.foregroundColor(.black)
.textSelection(.disabled)
.padding(5)
}
}
}
}
func latAsStr(_ lat: Double) -> String {
// convert lat to string
}
func lonAsStr(_ lon: Double) -> String {
// convert lon to string
}
}
我也想添加点击事件,但保留默认的
Map
手势存在很多问题。我想出了一个处理 onTapGesture
的函数,该函数在 iOS 16 及更高版本中可用,对于旧版本,创建一个手势,然后返回点击的位置。
import SwiftUI
extension View {
func onTapGestureButCompatible(
coordinateSpace: CoordinateSpace = .local,
perform action: @escaping (CGPoint) -> Void
) -> some View {
if #available(iOS 16.0, *) {
return onTapGesture(count: 1, coordinateSpace: coordinateSpace, perform: action)
} else {
let drag = DragGesture(minimumDistance: 0,
coordinateSpace: coordinateSpace)
.onEnded { value in
action(value.location)
}
return simultaneousGesture(TapGesture().sequenced(before: drag))
}
}
}