Flutter中如何从ListTile获取坐标在Google Map加载所有Marker
Flutter GetX 实现客户经纬度转Google Map Marker 落地方案
核心实现逻辑
- 客户列表数据统一存在GetX全局控制器中,跨页面直接访问,避免路由传参的序列化开销与类型错误
- 经纬度字段提前做类型兜底转换,统一为
double类型,适配Google Map组件入参要求 - Marker生成阶段过滤非法坐标值,避免地图渲染崩溃
分步实现代码
1. 定义数据模型与GetX状态层
先统一数据结构,解决最常见的经纬度类型不匹配导致Marker不显示的问题:
import 'package:get/get.dart'; // 客户数据模型 class CustomerModel { final String customerName; final double partnerLatitude; final double partnerLongitude; CustomerModel({ required this.customerName, required this.partnerLatitude, required this.partnerLongitude, }); // 对齐原有JSON接口拉取逻辑,做类型兜底 factory CustomerModel.fromJson(Map<String, dynamic> json) { return CustomerModel( customerName: json['partner_name'] ?? '未知客户', // 接口返回String/int类型都统一转double,避免类型报错 partnerLatitude: double.tryParse(json['partner_latitude'].toString()) ?? 0, partnerLongitude: double.tryParse(json['partner_longitude'].toString()) ?? 0, ); } } class CustomerController extends GetxController { // 响应式客户列表,和你原有拉取接口的逻辑对齐 RxList<CustomerModel> customerList = <CustomerModel>[].obs; Future<void> loadCustomerData() async { // 保留你原有JSON接口拉取逻辑,拉取完成后给customerList赋值即可 // 示例: // final apiRes = await yourCustomerApi.getList(); // customerList.assignAll(apiRes.map((e) => CustomerModel.fromJson(e)).toList()); } }
注意:Google Map的LatLng构造只接受double类型入参,直接传String类型经纬度是Marker加载失败的最高发原因
2. Home页跳转逻辑
不需要把整个客户列表作为路由参数传递,直接跳转即可,全局状态跨页面可直接访问:
// Home页内跳转地图的按钮点击事件 onPressed: () { // 直接跳转,无需传参 Get.to(() => const MapMarkersPage()); }
3. MapMarkers页Marker渲染逻辑
页面初始化时直接从GetX控制器取客户列表,遍历生成Marker集合:
import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:get/get.dart'; class MapMarkersPage extends StatefulWidget { const MapMarkersPage({super.key}); @override State<MapMarkersPage> createState() => _MapMarkersPageState(); } class _MapMarkersPageState extends State<MapMarkersPage> { late CameraPosition initialCameraPos; final Set<Marker> _allMarkers = {}; // 直接获取全局已存在的客户控制器实例 final CustomerController _customerController = Get.find<CustomerController>(); @override void initState() { super.initState(); _initMapConfig(); } void _initMapConfig() { // 空列表兜底 if (_customerController.customerList.isEmpty) { initialCameraPos = const CameraPosition(target: LatLng(39.90, 116.40), zoom: 12); setState(() {}); return; } // 初始地图定位取第一个客户的坐标 final firstCustomer = _customerController.customerList.first; initialCameraPos = CameraPosition( target: LatLng(firstCustomer.partnerLatitude, firstCustomer.partnerLongitude), zoom: 12, ); // 遍历生成所有客户Marker for (final customer in _customerController.customerList) { // 过滤非法坐标,避免地图崩溃 if (customer.partnerLatitude < -90 || customer.partnerLatitude > 90) continue; if (customer.partnerLongitude < -180 || customer.partnerLongitude > 180) continue; _allMarkers.add( Marker( // markerId必须全局唯一,重复ID会导致Marker被覆盖不显示 markerId: MarkerId(customer.customerName), position: LatLng(customer.partnerLatitude, customer.partnerLongitude), infoWindow: InfoWindow(title: customer.customerName), ), ); } setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('客户分布地图')), body: GoogleMap( initialCameraPosition: initialCameraPos, markers: _allMarkers, // 原有地图配置项(比如定位开关、地图样式等)可正常保留 ), ); } }
常见问题排查
- 确认Android端
AndroidManifest.xml、iOS端Info.plist中已正确配置Google Map API Key,权限声明完整 - 每个Marker的
markerId不能重复,建议用客户唯一ID作为标识,不要用固定字符串 - 如果页面加载后Marker为空,先打印
_customerController.customerList长度,确认页面跳转前客户数据已经成功拉取赋值 - 不要在MapMarkers页重复调用
Get.put(CustomerController()),会重新创建空的控制器实例,导致拿不到已有客户数据,统一用Get.find()获取已初始化的实例
内容的提问来源于stack exchange,提问作者Zakaria Hamid
相关产品推荐
相关产品推荐

