Swift4中GoogleMaps路径显示及跨控制器两点耗时绘制问题
在Swift 4中实现Google Maps路径显示与跨控制器地点耗时计算
一、先搞定跨控制器的地点数据传递
你已经在HomeViewController里通过PickupLocationDelegate拿到了第一个地点(起点),现在需要处理第二个地点(终点)的获取和传递。这里推荐用Delegate模式或者闭包回调,比通知更清晰,耦合性更低:
1. 定义终点选择的Delegate协议
假设第二个地点来自DestinationViewController,先定义一个代理协议:
protocol DestinationLocationDelegate: AnyObject { func didSelectDestinationPlace(place: GooglePlaceModel?) }
2. 在终点选择控制器中添加代理属性
class DestinationViewController: UIViewController { weak var delegate: DestinationLocationDelegate? // 假设用户选择终点后触发这个方法 func userConfirmedDestination(_ selectedPlace: GooglePlaceModel) { delegate?.didSelectDestinationPlace(place: selectedPlace) navigationController?.popViewController(animated: true) } }
3. 在HomeViewController中保存双地点并触发后续逻辑
让HomeViewController遵守新的Delegate,同时保存起点和终点,拿到双地点后就可以调用路径绘制和耗时计算:
class HomeViewController: UIViewController, PickupLocationDelegate, DestinationLocationDelegate { // 存储起点和终点 private var pickupPlace: GooglePlaceModel? private var destinationPlace: GooglePlaceModel? // 你的现有代码:获取起点 func didSelectLocation(place: GooglePlaceModel?) { guard let place = place else { return } pickupPlace = place enter_Location_TF.text = place.name customDirectionViewTwo.isHidden = false direction_Button.isHidden = true location_Button.setImage(UIImage(named: "directionPoint")?.withRenderingMode(.alwaysOriginal), for: .normal) } // 新增:获取终点并触发路线逻辑 func didSelectDestinationPlace(place: GooglePlaceModel?) { guard let place = place else { return } destinationPlace = place // 双地点都已获取,开始请求路线 fetchRouteAndDuration() } // 跳转到终点选择页时设置代理 func navigateToDestinationPicker() { let destVC = DestinationViewController() destVC.delegate = self navigationController?.pushViewController(destVC, animated: true) } }
二、调用Google Directions API获取路线与耗时
要显示路径和计算耗时,需要调用Google Directions API,拿到路线坐标和时长数据:
1. 配置API密钥并发起网络请求
确保你已经集成Google Maps SDK,且API密钥启用了Directions API:
import GoogleMaps // 替换为你的Google API密钥 let googleAPIKey = "YOUR_GOOGLE_API_KEY" extension HomeViewController { func fetchRouteAndDuration() { guard let pickup = pickupPlace, let destination = destinationPlace else { print("缺少起点或终点数据") return } // 构造API请求URL let origin = "\(pickup.lat),\(pickup.lng)" let destCoord = "\(destination.lat),\(destination.lng)" let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destCoord)&key=\(googleAPIKey)" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { [weak self] data, _, error in guard let self = self, let data = data, error == nil else { print("路线请求失败:\(error?.localizedDescription ?? "未知错误")") return } do { // 用Codable解析API响应 let response = try JSONDecoder().decode(DirectionsResponse.self, from: data) DispatchQueue.main.async { self.drawRouteOnMap(with: response) self.showTravelDuration(from: response) } } catch { print("路线数据解析失败:\(error.localizedDescription)") } }.resume() } }
2. 定义Codable模型解析响应
简化版的模型,可根据需求扩展:
struct DirectionsResponse: Codable { let routes: [Route] } struct Route: Codable { let legs: [Leg] let overview_polyline: Polyline } struct Leg: Codable { let duration: Duration } struct Duration: Codable { let text: String // 格式化时长,如"20 mins" let value: Int // 秒数 } struct Polyline: Codable { let points: String // 编码的路线坐标字符串 }
三、在Google Map上绘制路径
拿到编码的坐标串后,解码并绘制Polyline:
extension HomeViewController { func drawRouteOnMap(with response: DirectionsResponse) { guard let route = response.routes.first else { return } // 解码Polyline坐标 let path = GMSPath(fromEncodedPath: route.overview_polyline.points) let polyline = GMSPolyline(path: path) polyline.strokeWidth = 4.0 polyline.strokeColor = UIColor.systemBlue // 假设你的地图视图是mapView polyline.map = self.mapView // 调整地图视角,完整显示路线 let bounds = GMSCoordinateBounds(path: path!) let cameraUpdate = GMSCameraUpdate.fit(bounds, withPadding: 50.0) self.mapView.moveCamera(cameraUpdate) } }
四、显示两点间的预计耗时
从API响应中提取时长数据,显示到UI上:
extension HomeViewController { func showTravelDuration(from response: DirectionsResponse) { guard let leg = response.routes.first?.legs.first else { return } let durationText = leg.duration.text // 假设你有一个UILabel用于显示耗时 durationLabel.text = "预计耗时:\(durationText)" } }
关键注意事项
- 确保你的
GooglePlaceModel包含lat(纬度)和lng(经度)属性,否则无法构造API请求。 - 在
Info.plist中添加NSLocationWhenInUseUsageDescription,Google Maps需要位置权限才能正常工作。 - 要处理网络请求失败的场景,比如给用户弹出提示框。
- 如果需要实时更新路线,可以监听用户位置变化,重新发起路线请求。
内容的提问来源于stack exchange,提问作者Rohit
相关产品推荐
相关产品推荐

