如何在SwiftUI的Mapbox v10中实现点击地图获取坐标并添加标记
在SwiftUI的Mapbox地图中实现点击获取坐标并添加标记
你需要在SwiftUI集成的Mapbox地图中检测点击操作,获取坐标并添加标记,已在Android和React环境实现,现在需要适配SwiftUI环境,现有代码如上。
实现步骤及修改代码
1. 改造MapBoxMapView,添加坐标回调绑定
给UIViewControllerRepresentable添加绑定变量,用于传递点击坐标,同时设置回调闭包让MapViewController能通知点击事件:
import SwiftUI import UIKit import MapboxMaps struct MapBoxMapView: UIViewControllerRepresentable { @Binding var tappedCoordinate: CLLocationCoordinate2D? func makeUIViewController(context: Context) -> MapViewController { let vc = MapViewController() vc.onMapTapped = { coordinate in self.tappedCoordinate = coordinate vc.addMarker(at: coordinate) } return vc } func updateUIViewController(_ uiViewController: MapViewController, context: Context) { } }
2. 修改MapViewController,添加点击监听与标记管理
在控制器中添加手势识别器处理点击,同时用Mapbox的PointAnnotationManager管理标记:
class MapViewController: UIViewController { internal var mapView: MapView! var onMapTapped: ((CLLocationCoordinate2D) -> Void)? private var annotationManager: PointAnnotationManager! override func viewDidLoad() { super.viewDidLoad() let myResourceOptions = ResourceOptions(accessToken: "MY_TOKEN") let myCameraOptions = CameraOptions(center: CLLocationCoordinate2D(latitude: 0, longitude: 0), zoom: 10) let initOptions = MapInitOptions( resourceOptions: myResourceOptions, cameraOptions: myCameraOptions, styleURI: StyleURI.satellite ) mapView = MapView(frame: view.bounds, mapInitOptions: initOptions) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.view.addSubview(mapView) // 等待地图样式加载完成后初始化标记管理器 mapView.mapboxMap.onNext(.styleLoaded) { [weak self] _ in guard let self = self else { return } do { self.annotationManager = try self.mapView.annotations.makePointAnnotationManager() } catch { print("初始化标记管理器失败: \(error.localizedDescription)") } } // 添加点击手势识别器 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleMapTap(_:))) tapGesture.delegate = self mapView.addGestureRecognizer(tapGesture) } @objc private func handleMapTap(_ gesture: UITapGestureRecognizer) { guard gesture.state == .ended else { return } let tapPoint = gesture.location(in: mapView) if let coordinate = mapView.mapboxMap.coordinate(for: tapPoint) { onMapTapped?(coordinate) } } // 添加标记方法,可自定义标记内容 func addMarker(at coordinate: CLLocationCoordinate2D) { // 可选:清空已有标记 annotationManager.annotations.removeAll() let annotation = PointAnnotation(coordinate: coordinate) annotation.title = "点击位置" annotation.subtitle = String(format: "%.4f, %.4f", coordinate.latitude, coordinate.longitude) annotationManager.annotations.append(annotation) } } // 处理手势冲突,确保点击手势正常触发 extension MapViewController: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } }
3. 在SwiftUI主视图中使用
struct ContentView: View { @State private var tappedCoordinate: CLLocationCoordinate2D? var body: some View { MapBoxMapView(tappedCoordinate: $tappedCoordinate) .edgesIgnoringSafeArea(.all) } }
关键说明
- 点击坐标转换:通过
UITapGestureRecognizer获取屏幕点击位置,再用mapView.mapboxMap.coordinate(for:)转换为地理坐标。 - 标记管理:使用Mapbox v10推荐的
PointAnnotationManager管理标记,需要等待地图样式加载完成后初始化,避免崩溃。 - 手势冲突处理:实现
UIGestureRecognizerDelegate允许自定义手势与Mapbox自带手势同时识别,确保点击事件能正常触发。
内容的提问来源于stack exchange,提问作者Afonso Fonseca
相关产品推荐
相关产品推荐

