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 标签区分点击对象,实现多边形点击识别:
- 添加状态变量存储选中元素:
@State private var selectedMapElement: MapElement?
- 修改地图内容和点击逻辑:
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
相关产品推荐
相关产品推荐

