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

SwiftUI封装Google地图时GMSMarker点击跳转及delegate设置问题

核心实现逻辑
  • 不能直接将GMSMapView.delegate设置为GoogleMapView本身:GoogleMapView是值类型结构体,不满足代理要求的类类型约束
  • 必须使用UIViewRepresentable配套的Coordinator协调器作为代理实现载体,这是SwiftUI桥接UIKit控件时处理代理事件的标准方案
  • 你原有代码中mapView.delegate = ViewController()的写法是无效的,临时创建的ViewController实例在方法执行完就会被释放,代理回调完全无法触发
完整实现代码
import SwiftUI
import GoogleMaps

struct GoogleMapView: UIViewRepresentable {
    // 点击Marker的回调闭包,用于向SwiftUI层传递事件
    var onMarkerTapped: (GMSMarker) -> Void
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    func updateUIView(_ uiView: GMSMapView, context: Context) {
        let marker = GMSMarker()
        marker.position = CLLocationCoordinate2D(latitude: 20, longitude: 50)
        marker.map = uiView
    }

    func makeUIView(context: Context) -> GMSMapView {
        let camera = GMSCameraPosition.camera(withLatitude: 20, longitude: 50, zoom: 10)
        let mapView = GMSMapView(frame: .zero, camera: camera)
        // 核心:将delegate设置为上下文中的协调器实例
        mapView.delegate = context.coordinator
        return mapView
    }
    
    // 内部协调器类,实现GMSMapViewDelegate协议
    class Coordinator: NSObject, GMSMapViewDelegate {
        var parent: GoogleMapView
        
        init(parent: GoogleMapView) {
            self.parent = parent
        }
        
        // 实现Marker点击的代理回调
        func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
            parent.onMarkerTapped(marker)
            // 返回true表示已自定义处理事件,不需要触发地图默认点击行为
            return true
        }
    }
}
SwiftUI层调用示例(实现跳转逻辑)
struct ContentView: View {
    @State private var isShowDetail = false
    @State private var tappedMarker: GMSMarker?
    
    var body: some View {
        NavigationStack {
            GoogleMapView { marker in
                // 收到Marker点击事件,触发跳转
                tappedMarker = marker
                isShowDetail = true
            }
            .ignoresSafeArea()
            // 用sheet/push都可以实现跳转,这里以sheet为例
            .sheet(isPresented: $isShowDetail) {
                MarkerDetailView(marker: $tappedMarker)
            }
        }
    }
}

// 示例跳转目标视图
struct MarkerDetailView: View {
    @Binding var marker: GMSMarker?
    
    var body: some View {
        VStack(spacing: 20) {
            Text("你点击了Marker")
            Text("坐标:\(marker?.position.latitude ?? 0), \(marker?.position.longitude ?? 0)")
        }
        .padding()
    }
}

内容的提问来源于stack exchange,提问作者Santanu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:57:01