You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:15:49