Swift实现UITextField下方Google Places自动补全及经纬度获取问题
解决Google Places自动补全列表未显示在UITextField正下方的问题 + 经纬度获取方案
嘿,我之前也踩过Google Places自动补全列表位置跑偏的坑!结合官方SDK的正确用法,给你一套既能解决位置偏移问题,又能顺利获取经纬度的完整方案:
核心思路
默认的GMSAutocompleteViewController是全屏弹窗,不符合我们要在TextField下方显示列表的需求。所以我们要改用GMSAutocompleteResultsViewController,手动控制它的容器视图位置,精准定位到当前编辑的TextField正下方。
完整代码实现
1. 初始化相关变量与视图
首先在你的ViewController里声明必要的变量,初始化自动补全控制器和承载列表的容器视图:
import GooglePlaces class DeliveryViewController: UIViewController { @IBOutlet weak var pickupTextField: UITextField! @IBOutlet weak var dropoffTextField: UITextField! // 自动补全结果控制器 private var autocompleteResultsVC: GMSAutocompleteResultsViewController! // 承载自动补全列表的容器(用来控制位置和样式) private var autocompleteContainer: UIView! // 记录当前正在编辑的TextField,用于定位列表 private var activeTextField: UITextField? }
2. 配置视图与事件监听
在viewDidLoad里完成初始化、代理设置和事件绑定:
override func viewDidLoad() { super.viewDidLoad() // 初始化自动补全结果控制器并设置代理 autocompleteResultsVC = GMSAutocompleteResultsViewController() autocompleteResultsVC.delegate = self // 创建列表容器视图,初始隐藏,添加阴影和圆角优化样式 autocompleteContainer = UIView() autocompleteContainer.backgroundColor = .white autocompleteContainer.layer.cornerRadius = 8 autocompleteContainer.layer.shadowColor = UIColor.black.cgColor autocompleteContainer.layer.shadowOpacity = 0.15 autocompleteContainer.layer.shadowOffset = CGSize(width: 0, height: 2) autocompleteContainer.layer.shadowRadius = 6 autocompleteContainer.isHidden = true view.addSubview(autocompleteContainer) // 将自动补全控制器的视图添加到容器中 addChild(autocompleteResultsVC) autocompleteContainer.addSubview(autocompleteResultsVC.view) autocompleteResultsVC.didMove(toParent: self) // 绑定TextField的编辑事件 pickupTextField.addTarget(self, action: #selector(textFieldDidBeginEditing(_:)), for: .editingDidBegin) dropoffTextField.addTarget(self, action: #selector(textFieldDidBeginEditing(_:)), for: .editingDidBegin) pickupTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) dropoffTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) // 点击空白处隐藏列表并收起键盘 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideAutocompleteList)) view.addGestureRecognizer(tapGesture) }
3. 处理TextField交互与列表位置计算
这部分是解决位置问题的关键,精准计算容器视图的位置,让它刚好显示在当前TextField正下方:
@objc private func textFieldDidBeginEditing(_ textField: UITextField) { activeTextField = textField // 显示列表并更新位置 autocompleteContainer.isHidden = false updateAutocompleteListFrame() } @objc private func textFieldDidChange(_ textField: UITextField) { // 将输入内容传给自动补全控制器进行搜索 autocompleteResultsVC.sourceTextHasChanged(textField.text ?? "") } @objc private func hideAutocompleteList() { autocompleteContainer.isHidden = true activeTextField?.resignFirstResponder() activeTextField = nil } // 核心方法:计算列表的正确位置 private func updateAutocompleteListFrame() { guard let textField = activeTextField else { return } // 先刷新TextField布局,避免AutoLayout导致坐标错误 textField.layoutIfNeeded() // 将TextField的坐标转换到当前ViewController的view坐标系下 let textFieldFrame = textField.convert(textField.bounds, to: view) // 设置容器位置:TextField底部下方4px,宽度与TextField一致,高度设为200 let containerFrame = CGRect( x: textFieldFrame.origin.x, y: textFieldFrame.origin.y + textFieldFrame.size.height + 4, width: textFieldFrame.size.width, height: 200 ) autocompleteContainer.frame = containerFrame // 让自动补全视图铺满容器 autocompleteResultsVC.view.frame = autocompleteContainer.bounds }
4. 实现代理方法获取地点与经纬度
通过GMSAutocompleteResultsViewControllerDelegate获取用户选中的地点信息,包括经纬度:
extension DeliveryViewController: GMSAutocompleteResultsViewControllerDelegate { func resultsController(_ resultsController: GMSAutocompleteResultsViewController, didAutocompleteWith place: GMSPlace) { // 将选中的地点名称填充到当前TextField activeTextField?.text = place.name // 获取经纬度 let selectedLatitude = place.coordinate.latitude let selectedLongitude = place.coordinate.longitude print("选中地点经纬度:\(selectedLatitude), \(selectedLongitude)") // 隐藏列表并收起键盘 hideAutocompleteList() } func resultsController(_ resultsController: GMSAutocompleteResultsViewController, didFailAutocompleteWithError error: Error) { print("自动补全出错:\(error.localizedDescription)") } func didRequestAutocompletePredictions(_ resultsController: GMSAutocompleteResultsViewController) { UIApplication.shared.isNetworkActivityIndicatorVisible = true } func didUpdateAutocompletePredictions(_ resultsController: GMSAutocompleteResultsViewController) { UIApplication.shared.isNetworkActivityIndicatorVisible = false } }
注意事项
- 确保你的Google Cloud项目已经启用了Places API,并且配置的API_KEY拥有正确的权限,否则会无法获取搜索结果。
- 如果你的TextField使用AutoLayout布局,一定要在计算位置前调用
textField.layoutIfNeeded(),避免坐标计算偏差。 - 可以根据App的设计风格,调整列表容器的圆角、阴影、高度等样式参数,让它更贴合你的界面。
内容的提问来源于stack exchange,提问作者Fahad Baig
相关产品推荐
相关产品推荐

