如何使用GetX在Flutter中显示聚类质心标记?
问题:Flutter Map聚类标记无法显示,仅用户位置标记正常
我开发的Flutter应用基于flutter_map、get、LatLng2包,用GetX做状态管理,需求是从REST API拉取数据并在地图展示。目前用户位置标记能正常显示,但调用populateMarkers()获取的聚类质心标记始终无法渲染。
MapController代码
class MapAppController extends GetxController { LatLng center = LatLng(28.0339, 1.6596); Marker? userLocationMarker; bool isLoading = false; List<Marker> markers = []; Future<void> getLocation() async { isLoading = true; update(); LocationPermission permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { // TODO: 处理权限拒绝场景 } else if (permission == LocationPermission.deniedForever) { // TODO: 处理权限永久拒绝场景 } else { Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high); LatLng userLocation = LatLng(position.latitude, position.longitude); center = userLocation; userLocationMarker = Marker( width: 40.0, height: 40.0, point: userLocation, builder: (ctx) => const Icon( Icons.location_on, size: 45, color: Colors.red, ), ); isLoading = false; update(); } } Future<void> populateMarkers() async { isLoading = true; update(); final Map<String, LatLng> clustersCentroid = await DjangoHelper.getClusterCentroid(); markers.clear(); for (var cluster in clustersCentroid.entries) { markers.add( Marker( width: 80.0, height: 80.0, point: cluster.value, builder: (ctx) => const Icon( Icons.circle, size: 70, color: Colors.green, ), ), ); } isLoading = false; update(); } }
getLocation()方法运行正常,能正确展示用户位置标记;populateMarkers()会清空markers列表、为每个聚类创建标记并添加,最后调用update()触发UI重建,但聚类标记始终不显示。
地图页面代码
final mapController = Get.find<MapAppController>(); final userInfoController = Get.find<InscriptionController>(); class MapPage extends StatelessWidget { const MapPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: GetBuilder<MapAppController>( builder: (controller) => Stack( children: [ FlutterMap( options: MapOptions( center: controller.center, zoom: 5.0, ), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: const ['a', 'b', 'c'], ), MarkerLayer( markers: [ if (mapController.userLocationMarker != null) mapController.userLocationMarker!, if (mapController.markers.isNotEmpty) ...mapController.markers, ], ), ], ), Visibility( visible: mapController.isLoading, child: const CustomLoadingIndicator(), ), FloatingActionButton( onPressed: () async { await mapController.populateMarkers(); }, child: const Icon(Icons.info), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () async { await mapController.getLocation(); }, child: const Icon(Icons.gps_fixed), ), ); } }
问题原因及解决方法
1. 全局变量与GetBuilder实例不匹配
页面中直接使用全局的mapController变量,但GetBuilder的builder回调已经提供了当前监听的控制器实例,两者可能存在状态同步延迟。全部改用GetBuilder回调里的controller实例,避免直接引用全局变量:
// 修改MarkerLayer部分 MarkerLayer( markers: [ if (controller.userLocationMarker != null) controller.userLocationMarker!, ...controller.markers, ], ), // 修改Loading状态判断 Visibility( visible: controller.isLoading, child: const CustomLoadingIndicator(), ),
2. 列表内部变化未被GetX检测到
直接对markers列表执行clear()和add()操作,GetX无法感知列表内部的元素变化,导致update()无法触发正确的UI重建。有两种解决方式:
方案A:改用RxList
在控制器中声明可观察列表:
final markers = <Marker>[].obs;
populateMarkers()中添加标记的代码不变,页面中使用时转为普通列表:
...controller.markers.toList(),
方案B:创建新列表替换原列表
不要直接修改原列表,而是生成新列表替换:
// populateMarkers()中修改 final newMarkers = <Marker>[]; for (var cluster in clustersCentroid.entries) { newMarkers.add( Marker( width: 80.0, height: 80.0, point: cluster.value, builder: (ctx) => const Icon( Icons.circle, size: 70, color: Colors.green, ), ), ); } markers = newMarkers;
3. 验证API返回数据有效性
在populateMarkers()中添加日志,确认接口返回的聚类数据不为空且坐标有效:
print("聚类数据数量:${clustersCentroid.length}"); clustersCentroid.forEach((key, value) => print("聚类坐标:${value.latitude}, ${value.longitude}"));
4. 检查标记层级与可见性
聚类标记的绿色圆圈可能被用户位置标记遮挡,或地图缩放级别过低导致看不到。可以先注释用户位置标记的代码,单独测试聚类标记是否显示;或调整聚类标记的添加顺序(放在用户标记前面)提升层级。
内容的提问来源于stack exchange,提问作者Mikelenjilo
相关产品推荐
相关产品推荐

