iOS SwiftUI中Google Maps代理方法未触发问题求助
问题描述
通过SPM集成Google Maps后,地图可正常加载并显示多个标记,但mapViewDidFinishTileRendering(_:)和mapViewSnapshotReady(_:)等代理方法从未被调用,无法监听地图加载完成、地图移动等事件。
相关实现代码如下:
MapViewController 代码
import UIKit import GoogleMaps class MapViewController: UIViewController { var options = GMSMapViewOptions() var map = GMSMapView() var isAnimating: Bool = false override func loadView() { super.loadView() options.camera = GMSCameraPosition.camera(withLatitude: 18.659553, longitude: 78.105868, zoom: 17.0) options.frame = self.view.bounds map = GMSMapView(options: options) self.view = map } }
MapViewControllerBridge 代码
import Foundation import SwiftUI import GoogleMaps struct MapViewControllerBridge: UIViewControllerRepresentable { @Binding var markers: [GMSMarker] @Binding var selectedMarker: GMSMarker? var onAnimationEnded: () -> () var mapViewWillMove: (Bool) -> () func makeUIViewController(context: Context) -> MapViewController { let uiViewController = MapViewController() uiViewController.map.delegate = context.coordinator return uiViewController } func updateUIViewController(_ uiViewController: MapViewController, context: Context) { markers.forEach { $0.map = uiViewController.map } selectedMarker?.map = uiViewController.map animateToSelectedMarker(viewController: uiViewController) } func makeCoordinator() -> MapViewCoordinator { return MapViewCoordinator(self) } private func animateToSelectedMarker(viewController: MapViewController) { guard let selectedMarker = selectedMarker else { return } let map = viewController.map if map.selectedMarker != selectedMarker { map.selectedMarker = selectedMarker DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { map.animate(toZoom: kGMSMinZoomLevel) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position)) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { map.animate(toZoom: 12) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { onAnimationEnded() }) }) } } } } final class MapViewCoordinator: NSObject, GMSMapViewDelegate { var mapViewControllerBridge: MapViewControllerBridge init(_ mapViewControllerBridge: MapViewControllerBridge) { self.mapViewControllerBridge = mapViewControllerBridge } func mapView(_ mapView: GMSMapView, willMove gesture: Bool) { self.mapViewControllerBridge.mapViewWillMove(gesture) } func mapViewDidFinishTileRendering(_ mapView: GMSMapView) { print("Map Finished Rendering..") } func mapViewSnapshotReady(_ mapView: GMSMapView) { print("Map View Snapshot Ready..") } } }
ContentView 调用代码
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: { self.zoomInCenter = true }, mapViewWillMove: { (isGesture) in guard isGesture else { return } self.zoomInCenter = false }) .ignoresSafeArea()
解决方案
1. 替换已废弃的代理方法
mapViewDidFinishTileRendering(_:)和mapViewSnapshotReady(_:)已被Google Maps SDK标记为废弃,需使用最新替代方法:
- 监听地图渲染完成:使用
mapView(_:didFinishRenderingMap:fullyRendered:),该方法会在地图完成渲染时触发,fullyRendered参数可判断是否所有瓦片都加载完成。 - 监听快照就绪:使用
GMSMapView的snapshot(with:completionHandler:)方法,在回调中处理快照就绪逻辑。
修改后的MapViewCoordinator代码:
final class MapViewCoordinator: NSObject, GMSMapViewDelegate { var mapViewControllerBridge: MapViewControllerBridge init(_ mapViewControllerBridge: MapViewControllerBridge) { self.mapViewControllerBridge = mapViewControllerBridge } func mapView(_ mapView: GMSMapView, willMove gesture: Bool) { self.mapViewControllerBridge.mapViewWillMove(gesture) } func mapView(_ mapView: GMSMapView, didFinishRenderingMap fullyRendered: Bool) { if fullyRendered { print("Map fully rendered..") // 处理地图完全加载完成的逻辑 } else { print("Map partially rendered..") } } // 按需调用快照方法 func takeMapSnapshot(mapView: GMSMapView) { mapView.snapshot(with: nil) { image in guard let image = image else { return } print("Map snapshot ready..") // 处理快照图片 } } }
2. 确认代理设置逻辑
当前代码在makeUIViewController中设置代理的逻辑正确,需确保updateUIViewController中没有重置map.delegate的操作。现有代码仅添加标记,未修改代理,无需调整。
3. 排查地图移动事件
若mapView(_:willMove:)也未触发,可尝试延迟设置代理(用于排查,非最优解):
func makeUIViewController(context: Context) -> MapViewController { let uiViewController = MapViewController() DispatchQueue.main.async { uiViewController.map.delegate = context.coordinator } return uiViewController }
内容的提问来源于stack exchange,提问作者vishwa
相关产品推荐
相关产品推荐

