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

SwiftUI中如何通过经纬度利用PlacePicker类获取GMS位置名称

问题描述

我现有一个可通过搜索街道名称获取位置的PlacePicker组件(代码如下),希望在该类中添加giveLocationByLatLong(lat: Double, long: Double)方法,仅传入经纬度即可获取位置名称,请问该如何实现?是否可复用该类现有内容?

struct PlacePicker: UIViewControllerRepresentable {
        
    func makeCoordinator() -> GooglePlacesCoordinator {
        GooglePlacesCoordinator(self)
    }
    @Environment(\.presentationMode) var presentationMode
    @Binding var address: String
    @Binding var latitude: Double
    @Binding var longitude: Double
    
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<PlacePicker>) -> GMSAutocompleteViewController {
        
        GMSPlacesClient.provideAPIKey("xxxx")

        let autocompleteController = GMSAutocompleteViewController()
        autocompleteController.delegate = context.coordinator
        

        let fields: GMSPlaceField = GMSPlaceField(rawValue:UInt(GMSPlaceField.name.rawValue) |
                                                                  UInt(GMSPlaceField.placeID.rawValue) |
                                                                  UInt(GMSPlaceField.coordinate.rawValue) |
                                                                  GMSPlaceField.addressComponents.rawValue |
                                                                  GMSPlaceField.formattedAddress.rawValue)
        autocompleteController.placeFields = fields

        let filter = GMSAutocompleteFilter()
        filter.type = .address
        autocompleteController.autocompleteFilter = filter
        return autocompleteController
    }

    func updateUIViewController(_ uiViewController: GMSAutocompleteViewController, context: UIViewControllerRepresentableContext<PlacePicker>) {
    }

    class GooglePlacesCoordinator: NSObject, UINavigationControllerDelegate, GMSAutocompleteViewControllerDelegate {

        var parent: PlacePicker

        init(_ parent: PlacePicker) {
            self.parent = parent
        }

        func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
            DispatchQueue.main.async {
                print(place.description.description as Any)
                self.parent.address =  place.formattedAddress ?? "adresa gresita"
                self.parent.presentationMode.wrappedValue.dismiss()
                
                self.parent.latitude=place.coordinate.latitude
                self.parent.longitude=place.coordinate.longitude
            }
        }

        func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
            print("Error: ", error.localizedDescription)
        }

        func wasCancelled(_ viewController: GMSAutocompleteViewController) {
            parent.presentationMode.wrappedValue.dismiss()
        }

    }
}
实现方案

完全可以复用现有类的资源(比如已配置的GMSPlacesClient),核心是调用Google Places的逆地理编码接口完成经纬度到地址名称的解析,具体实现如下:

步骤1:在PlacePicker中新增目标方法

直接在结构体中添加giveLocationByLatLong方法,利用GMSPlacesClient的逆地理编码能力:

struct PlacePicker: UIViewControllerRepresentable {
    // 原有代码保持不变...
    
    // 新增:经纬度转地址名称方法
    func giveLocationByLatLong(lat: Double, long: Double, completion: @escaping (String?, Error?) -> Void) {
        // 复用原有API Key配置逻辑
        GMSPlacesClient.provideAPIKey("xxxx")
        
        let targetCoordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
        // 复用原有字段定义,或按需精简(这里只保留地址相关字段)
        let requiredFields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.formattedAddress.rawValue) | UInt(GMSPlaceField.name.rawValue))
        
        GMSPlacesClient.shared().fetchPlace(fromCoordinate: targetCoordinate, placeFields: requiredFields) { place, error in
            DispatchQueue.main.async {
                if let error = error {
                    completion(nil, error)
                    return
                }
                // 优先返回格式化地址,无则返回地点名称
                let resolvedAddress = place?.formattedAddress ?? place?.name ?? "无法获取地址"
                completion(resolvedAddress, nil)
            }
        }
    }
    
    // 原有代码保持不变...
}

步骤2:复用现有资源说明

  • API Key配置:直接复用原代码中GMSPlacesClient.provideAPIKey的逻辑,无需重复初始化;
  • 字段定义:可以直接使用原代码中定义的fields常量,或根据需求精简字段以减少请求数据量;
  • 线程处理:和原代码一致,将回调结果切回主线程,避免UI更新时的线程冲突。

调用示例

在使用PlacePicker的上下文里,可这样调用该方法:

let placePicker = PlacePicker(address: .constant(""), latitude: .constant(0), longitude: .constant(0))
placePicker.giveLocationByLatLong(lat: 39.9042, long: 116.4074) { address, error in
    if let validAddress = address {
        print("解析得到的地址:\(validAddress)")
        // 可直接更新绑定的address变量或其他UI操作
        // self.boundAddress = validAddress
    } else if let err = error {
        print("解析失败:\(err.localizedDescription)")
    }
}

注意事项

  • 确保Google Places SDK已正确集成,且API Key拥有Geocoding API的调用权限;
  • 逆地理编码有请求配额限制,需控制调用频率;
  • 如果需要更新PlacePicker绑定的address等变量,需确保在可修改绑定的上下文(如父视图)中调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:50:15