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

iOS 18中MapKit地图点击获取坐标的替代方案问询

iOS 18 中 SwiftUI Map 点击坐标获取的替代方案

一、原生 SwiftUI/MapKit 替代方案(iOS 18+)

iOS 18 官方废弃了 Map 上的 onTapGesture,同时推出了更贴合地图场景的交互 API,无需依赖 MapReader 和手动坐标转换即可实现需求:

1. 基础点击获取坐标

使用 Map 新增的 onTap(perform:) 修饰符,直接获取点击的地理坐标:

Map(scope: mapScope) {
    ForEach(drawBuildingsMarkers) { marker in
        Marker(marker.title, coordinate: marker.point)
    }
    
    if drawBuildingsMarkers.count > 2 {
        MapPolygon(coordinates: drawBuildingsMarkers.map { $0.point })
            .foregroundStyle(Color.red.opacity(0.5))
            .stroke(Color.red, lineWidth: 2)
    }
}
.onTap { context in
    // 提取点击的地理坐标
    guard let coordinate = context.coordinate else { return }
    let newMarker = DrawPoint(title: "Point \(drawBuildingsMarkers.count + 1)", point: coordinate)
    drawBuildingsMarkers.append(newMarker)
}

2. 检测 MKPolygon 点击

通过 MapElement 标签区分点击对象,实现多边形点击识别:

  1. 添加状态变量存储选中元素:
@State private var selectedMapElement: MapElement?
  1. 修改地图内容和点击逻辑:
Map(scope: mapScope) {
    ForEach(drawBuildingsMarkers) { marker in
        Marker(marker.title, coordinate: marker.point)
    }
    
    if drawBuildingsMarkers.count > 2 {
        MapPolygon(coordinates: drawBuildingsMarkers.map { $0.point })
            .foregroundStyle(Color.red.opacity(0.5))
            .stroke(Color.red, lineWidth: 2)
            .tag("TargetBuildingPolygon") // 给目标多边形打标签
    }
}
.onTap { context in
    // 优先处理地图元素点击
    if let element = context.selectedElement {
        selectedMapElement = element
        // 通过标签判断是否点击了目标多边形
        if element.tag as? String == "TargetBuildingPolygon" {
            print("Polygon tapped")
            // 这里添加多边形点击后的业务逻辑
        }
    } else if let coordinate = context.coordinate {
        // 空白区域点击,添加标记点
        let newMarker = DrawPoint(title: "Point \(drawBuildingsMarkers.count + 1)", point: coordinate)
        drawBuildingsMarkers.append(newMarker)
    }
}

迁移注意事项

  • 移除原代码中的 MapReader 和 GeometryProxy,新 API 直接返回地理坐标,无需屏幕坐标转换
  • 地图内置控件(指南针、定位按钮)会自动优先响应点击,无需额外层级处理

二、MapBox 替代方案

如果需要更灵活的地图交互或跨平台兼容,可迁移至 MapBox:

1. 基础点击获取坐标

集成 MapBox 后,使用其 MapboxMap 的 onMapTap 实现坐标获取:

import MapboxMaps

struct MapBoxBuildingView: View {
    @State private var drawBuildingsMarkers: [DrawPoint] = []
    @State private var mapView: MapView!
    
    var body: some View {
        ZStack {
            MapboxMap()
                .onMapTap { context in
                    let coordinate = context.coordinate
                    let newMarker = DrawPoint(title: "Point \(drawBuildingsMarkers.count + 1)", point: coordinate)
                    drawBuildingsMarkers.append(newMarker)
                    // 将标记添加到地图
                    let annotation = PointAnnotation(coordinate: coordinate)
                    annotation.title = newMarker.title
                    mapView.annotations.addAnnotation(annotation)
                }
                .onAppear {
                    mapView = MapView()
                    // 配置地图样式、定位权限等
                    mapView.location.updateSettings(.init(showsUserLocation: true))
                }
            
            // 自定义地图控件
            VStack {
                Button("定位") {
                    mapView.location.setCamera(to: .init(centerCoordinate: mapView.location.latestLocation?.coordinate ?? CLLocationCoordinate2D()))
                }
            }
            .padding()
            .background(.ultraThinMaterial)
        }
    }
}

2. 多边形点击检测

通过 MapBox 的图层系统实现多边形点击识别:

// 创建多边形数据源与图层
func addBuildingPolygon() {
    guard drawBuildingsMarkers.count > 2 else { return }
    let coordinates = drawBuildingsMarkers.map { $0.point }
    let polygon = Polygon(coordinates: coordinates)
    let source = GeoJSONSource(id: "building-polygon", geometry: polygon)
    
    let fillLayer = FillLayer(id: "building-fill", source: "building-polygon")
        .fillColor(.constant(Color.red.opacity(0.5)))
    let lineLayer = LineLayer(id: "building-line", source: "building-polygon")
        .lineColor(.constant(Color.red))
        .lineWidth(.constant(2))
    
    // 添加到地图
    mapView.style.addSource(source)
    mapView.style.addLayer(fillLayer)
    mapView.style.addLayer(lineLayer)
    
    // 监听多边形点击
    mapView.onLayerTap(layerId: "building-fill") { _ in
        print("MapBox polygon tapped")
        return true
    }
}

内容的提问来源于stack exchange,提问作者Jean Gabriel Greco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 03:10:59