Flutter中基于MapMyIndia实现无密钥地址自动补全搜索方案
Flutter 实现地址自动补全(无MapMyIndia密钥,结合location & geocode依赖)
实现方案
由于无法使用MapMyIndia的SDK/API密钥,我们可以利用已引入的location和geocode包,通过地理编码服务实现地址自动补全效果——核心逻辑是监听用户输入的关键词,调用地理编码接口返回匹配的地址(含经纬度),并展示为可选列表。
1. 确认依赖配置
确保pubspec.yaml中依赖配置正确:
dependencies: flutter: sdk: flutter location: ^5.0.3 # 替换为最新稳定版 geocode: ^1.0.1 # 替换为最新稳定版
执行flutter pub get完成依赖安装。
2. 获取当前位置(优化搜索精度)
用location包获取设备当前经纬度,作为地址搜索的上下文,缩小匹配范围:
import 'package:location/location.dart'; Future<LocationData?> fetchCurrentLocation() async { final location = Location(); // 检查定位服务是否开启 bool serviceEnabled = await location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) return null; } // 检查定位权限 PermissionStatus permission = await location.hasPermission(); if (permission == PermissionStatus.denied) { permission = await location.requestPermission(); if (permission != PermissionStatus.granted) return null; } return await location.getLocation(); }
3. 地址自动补全核心逻辑
通过geocode包的正向地理编码能力,根据输入关键词获取匹配地址及经纬度:
import 'package:geocode/geocode.dart'; Future<List<Map<String, dynamic>>> getAddressSuggestions(String query, {LocationData? currentLoc}) async { final geoCode = GeoCode(); final suggestions = <Map<String, dynamic>>[]; try { // 执行正向地理编码查询 final results = await geoCode.forwardGeocoding(address: query); // 解析结果,提取地址文本和经纬度 for (final result in results.results) { suggestions.add({ 'address': result.formattedAddress, 'lat': result.geometry.location.lat, 'lng': result.geometry.location.lng, }); } } catch (e) { debugPrint('地址搜索失败: $e'); } return suggestions; }
4. UI实现搜索框与补全列表
构建带实时搜索功能的UI,展示地址建议列表:
import 'package:flutter/material.dart'; class AddressAutoCompletePage extends StatefulWidget { const AddressAutoCompletePage({super.key}); @override State<AddressAutoCompletePage> createState() => _AddressAutoCompletePageState(); } class _AddressAutoCompletePageState extends State<AddressAutoCompletePage> { final _searchController = TextEditingController(); List<Map<String, dynamic>> _suggestions = []; LocationData? _currentLocation; @override void initState() { super.initState(); // 初始化时获取当前位置 fetchCurrentLocation().then((loc) => setState(() => _currentLocation = loc)); // 监听输入变化触发搜索 _searchController.addListener(_handleSearchInputChange); } void _handleSearchInputChange() { final query = _searchController.text.trim(); if (query.isEmpty) { setState(() => _suggestions = []); return; } getAddressSuggestions(query, currentLoc: _currentLocation) .then((suggestions) => setState(() => _suggestions = suggestions)); } @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('地址自动补全')), body: Column( children: [ Padding( padding: const EdgeInsets.all(16), child: TextField( controller: _searchController, decoration: const InputDecoration( hintText: '输入地址关键词', border: OutlineInputBorder(), prefixIcon: Icon(Icons.search), ), ), ), Expanded( child: ListView.builder( itemCount: _suggestions.length, itemBuilder: (ctx, idx) { final item = _suggestions[idx]; return ListTile( title: Text(item['address']), subtitle: Text('${item['lat']}, ${item['lng']}'), onTap: () { // 处理地址选中逻辑 print('选中地址: ${item['address']}'); }, ); }, ), ), ], ), ); } }
关键说明
- 该方案依赖
geocode包默认的地理编码服务,若需指定MapMyIndia的地理编码服务,需确认geocode包是否支持自定义服务端点(通常需要配置密钥,不符合需求,因此采用默认服务替代)。 - 若遇到地理编码服务限制,可添加输入防抖(延迟500ms再发起请求),避免频繁调用接口。
内容的提问来源于stack exchange,提问作者Ranjan Kumar
相关产品推荐
相关产品推荐

