如何用Flutter实现基于Google Places API的地址输入下拉建议
实现Flutter端Google Places地址输入建议功能
嘿,刚好我之前做过类似的Flutter地址输入功能,其实实现起来真的没那么麻烦!虽然Flutter官方确实没有开箱即用的组件,但结合Google Places API,咱们一步步来就能搞定~
1. 前期准备
- 先去Google Cloud控制台启用Places API,生成专属的API密钥,记得给密钥配置应用限制(比如绑定Android的包名、SHA-1指纹,iOS的Bundle ID),避免被恶意调用。
- 如果选择手动调用API,需要添加
http包到pubspec.yaml;如果用第三方包简化开发,可以选社区成熟的flutter_google_places。
2. 两种实现方案
方案一:手动调用API(自定义程度更高)
这种方式适合需要完全自定义UI的场景,步骤如下:
- 用
TextField作为输入载体,监听onChanged事件。这里一定要加防抖处理(比如用Timer延迟300ms再发送请求),避免用户每敲一个字符就发起一次API调用,既浪费资源又容易触发限流。 - 构造Google Places Autocomplete的请求URL,示例如下:
其中https://maps.googleapis.com/maps/api/place/autocomplete/json?input=用户输入内容&key=你的API密钥&components=country:cncomponents参数可以用来限制搜索国家(比如country:cn只搜中国境内地点),可选但推荐加上。 - 用
http包发送GET请求,解析返回的JSON数据,提取出地点名称、Place ID等核心信息。 - 在输入框下方展示建议列表(可以用
Stack+ListView或者Overlay实现悬浮列表),当用户点击某一项时,把选中的地点名称填充到输入框,还可以进一步调用Place Details API获取经纬度等详细信息。
方案二:用第三方包快速实现
如果不需要太复杂的自定义,社区的flutter_google_places包能帮咱们省不少事,示例代码如下:
import 'package:flutter_google_places/flutter_google_places.dart'; import 'package:google_maps_webservice/places.dart'; import 'package:flutter/material.dart'; class AddressInputPage extends StatefulWidget { const AddressInputPage({super.key}); @override State<AddressInputPage> createState() => _AddressInputPageState(); } class _AddressInputPageState extends State<AddressInputPage> { final TextEditingController _addressController = TextEditingController(); final String _apiKey = "你的API密钥"; final GoogleMapsPlaces _places = GoogleMapsPlaces(apiKey: "你的API密钥"); Future<void> _selectAddress() async { // 弹出地点选择界面 Prediction? selectedPlace = await PlacesAutocomplete.show( context: context, apiKey: _apiKey, mode: Mode.overlay, // 可选全屏模式Mode.fullscreen language: "zh-CN", components: const [Component(Component.country, "cn")], hint: "请输入地址", ); if (selectedPlace != null) { // 获取选中地点的详细信息 PlacesDetailsResponse detail = await _places.getDetailsByPlaceId(selectedPlace.placeId!); // 更新输入框内容 setState(() { _addressController.text = detail.result.name ?? ""; }); // 这里可以保存经纬度等信息 double latitude = detail.result.geometry!.location.lat; double longitude = detail.result.geometry!.location.lng; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("地址输入")), body: Padding( padding: const EdgeInsets.all(16.0), child: TextField( controller: _addressController, readOnly: true, // 让输入框只读,点击时触发选择逻辑 onTap: _selectAddress, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: "点击选择地址", suffixIcon: Icon(Icons.location_on), ), ), ), ); } }
3. 关键注意事项
- API密钥安全:绝对不要把API密钥硬编码在代码里!Android可以通过
local.properties配置,iOS用Info.plist管理,同时在Google Cloud控制台给密钥绑定应用的包名/指纹,进一步降低泄露风险。 - 错误处理:一定要处理网络请求失败、API返回错误(比如密钥无效、请求次数超限)的情况,给用户显示友好的提示,比如“网络异常,请稍后重试”。
- 用户体验优化:除了防抖,还可以在请求过程中显示加载动画,避免用户以为界面没反应;另外,建议列表的样式尽量和App整体风格统一,提升体验。
内容的提问来源于stack exchange,提问作者Gabe O'Leary
相关产品推荐
相关产品推荐

