如何在Swift中通过Firebase发送位置消息并实现Google Map动态取点
功能需求与当前实现问题
预期功能逻辑
- 用户点击按钮后弹出弹窗,提供音频、视频、位置三类消息发送选项
- 用户选择位置选项后跳转至locationViewController
- 最终将选中的位置存储到Firebase
当前已完成功能
- 静态坐标的Google Map加载与标记点渲染
- 在chatViewController中定义了InputActionSheet方法,用户点击选择按钮后触发该方法,调用位置消息相关逻辑
待解决问题
- 如何在用户点击Google Map任意位置时动态获取对应坐标
- 如何在用户点击位置时同步显示标记点
解决方案
修改逻辑说明
- 给位置选择页添加
GMSMapViewDelegate代理,通过代理方法获取用户点击的坐标 - 新增全局存储选中标记的属性,每次点击后替换旧标记,避免页面出现多个选中标记
- 新增回调闭包,等用户确认选中位置后再将坐标传回聊天页触发Firebase发送逻辑,修正原代码未等用户选择就提前发消息的问题
修改后完整代码
位置选择页面代码(原ViewController建议重命名为LocationPickerViewController避免重名)
class LocationPickerViewController: UIViewController { @IBOutlet weak var mapView: GMSMapView! let manager = CLLocationManager() // 存储当前选中的标记,方便后续替换 private var selectedMarker: GMSMarker? // 回调闭包:用户选完位置后把坐标传回聊天页 var didSelectLocation: ((CLLocationCoordinate2D) -> Void)? override func viewDidLoad() { super.viewDidLoad() // 设置mapView代理 mapView.delegate = self manager.delegate = self manager.requestWhenInUseAuthorization() manager.startUpdatingLocation() self.mapView.mapStyle(name:"darkTheme", type:"json") // 右上角添加确认发送按钮 navigationItem.rightBarButtonItem = UIBarButtonItem(title: "发送", style: .done, target: self, action: #selector(sendSelectedLocation)) } func setupMap(title:String,subtitle:String,_ coordinate:CLLocationCoordinate2D){ let camera = GMSCameraPosition.camera(withLatitude: coordinate.latitude, longitude: coordinate.longitude, zoom: 6.0) mapView.camera = camera self.addMarker(title: title, subtitle: subtitle, coordinate:coordinate) } func addMarker(title:String,subtitle:String,coordinate:CLLocationCoordinate2D){ let marker = GMSMarker() marker.icon = #imageLiteral(resourceName: "DiceFive") marker.position = coordinate marker.title = title marker.snippet = subtitle marker.map = mapView } // 确认发送选中位置 @objc private func sendSelectedLocation() { guard let coordinate = selectedMarker?.position else { // 可自行添加提示要求用户先选择位置 return } didSelectLocation?(coordinate) navigationController?.popViewController(animated: true) } } // 实现GMSMapViewDelegate处理地图点击事件 extension LocationPickerViewController: GMSMapViewDelegate { func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) { // 移除上一次的选中标记 selectedMarker?.map = nil // 新建选中标记 let newMarker = GMSMarker() newMarker.icon = #imageLiteral(resourceName: "DiceFive") // 可替换为自定义选中态图标 newMarker.position = coordinate newMarker.title = "选中位置" newMarker.map = mapView // 存储当前选中标记 selectedMarker = newMarker // 可选:将选中位置移到地图中心 mapView.animate(to: GMSCameraPosition.camera(withTarget: coordinate, zoom: mapView.camera.zoom)) } } extension LocationPickerViewController : CLLocationManagerDelegate { public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.first else{ return } // 可选:默认将地图定位到用户当前位置 mapView.animate(to: GMSCameraPosition.camera(withTarget: location.coordinate, zoom: 15.0)) // 拿到位置后停止更新节省电量 manager.stopUpdatingLocation() } }
聊天页presentLocationPicker方法修改后代码
private func presentLocationPicker() { let vc = LocationPickerViewController() vc.title = "选择位置" vc.navigationItem.largeTitleDisplayMode = .never // 监听位置选择回调 vc.didSelectLocation = { [weak self] selectedCoordinate in guard let strongSelf = self else { return } let location = Location(location: CLLocation(latitude: selectedCoordinate.latitude, longitude: selectedCoordinate.longitude), size: .zero) let messageId = UUID().uuidString // 自行生成唯一消息ID let message = Message(sender: strongSelf.selfSender,messageId: messageId,sentDate: Date(),kind: .location(location)) DatabaseManager.shared.sendMessage(to: strongSelf.conversationId, otherUserEmail: strongSelf.otherUserEmail, name: strongSelf.name, newMessage: message, completion: { success in if success { print("位置消息发送成功") } else { print("位置消息发送失败") } }) } navigationController?.pushViewController(vc, animated: true) }
内容的提问来源于stack exchange,提问作者Faheem
相关产品推荐
相关产品推荐

