Flutter Google Maps:无需点击Marker即可显示所有InfoWindow标题
解决google_maps_flutter地图加载完成后自动显示所有Marker的InfoWindow问题
首先要明确两个核心点:
- 原生Android/iOS地图SDK默认仅支持同时显示一个InfoWindow,显示新的会自动关闭已打开的。如果要同时展示多个,只能通过自定义组件实现。
- 你提供的代码存在两处问题:方法名拼写错误(
_onCameraIde应为_onCameraIdle),且调用时机不对——地图刚创建时Marker可能还未完成渲染,直接调用showMarkerInfoWindow会无效。
方案1:依次显示InfoWindow(原生支持)
如果接受一次显示一个InfoWindow(或依次轮显),可以按以下步骤实现:
- 正确获取MapController,在
onMapCreated回调中完成初始化:
Completer<GoogleMapController> _controller = Completer(); // GoogleMap组件配置 GoogleMap( onMapCreated: (GoogleMapController controller) { _controller.complete(controller); // 地图创建完成后延迟片刻,确保Marker渲染完毕再执行 Future.delayed(const Duration(milliseconds: 500), _showAllInfoWindows); }, markers: markerSet, initialCameraPosition: const CameraPosition(target: LatLng(37.7749, -122.4194), zoom: 12), // 其他地图配置... )
- 实现批量显示InfoWindow的方法,用for循环+await确保每个调用生效:
void _showAllInfoWindows() async { final mapController = await _controller.future; for (final marker in markerSet) { await mapController.showMarkerInfoWindow(marker.markerId); // 可选:添加小延迟避免频繁调用导致的异常 await Future.delayed(const Duration(milliseconds: 100)); } }
方案2:同时显示多个自定义InfoWindow(原生不支持,需自定义)
如果需要同时展示所有Marker的标题,只能通过在地图上层叠加自定义文本组件实现:
- 准备存储Marker位置和标题的列表(从markerSet转换):
List<Map<String, dynamic>> _markerInfos = []; // 在markerSet初始化后转换 _markerInfos = markerSet.map((marker) { return { 'position': marker.position, 'title': marker.infoWindow.title, }; }).toList();
- 使用Stack将GoogleMap和自定义文本组件叠加:
Stack( children: [ GoogleMap( onMapCreated: (controller) => _controller.complete(controller), markers: markerSet, initialCameraPosition: const CameraPosition(target: LatLng(37.7749, -122.4194), zoom: 12), ), // 遍历生成自定义InfoWindow ..._markerInfos.map((info) { return FutureBuilder<ScreenCoordinate>( future: _controller.future.then((controller) => controller.getScreenCoordinate(info['position'])), builder: (context, snapshot) { if (!snapshot.hasData) return const SizedBox(); final coord = snapshot.data!; return Positioned( left: coord.x.toDouble(), top: coord.y.toDouble() - 30, // 调整偏移避免遮挡Marker child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 2)], ), child: Text(info['title'] ?? '', style: const TextStyle(fontSize: 12)), ), ); }, ); }), ], )
- 补充处理地图移动时的位置更新:
在GoogleMap组件中添加onCameraMove回调,触发自定义InfoWindow的位置刷新(可结合状态管理实现):
onCameraMove: (_) { // 触发状态更新,重新计算所有自定义InfoWindow的位置 setState(() {}); },
补充说明
- 如果使用方案1,
onCameraIdle可作为备选触发时机,但需加判断避免地图每次停止移动都重复执行。 - 自定义InfoWindow需处理地图缩放、移动时的位置同步,上述示例用
FutureBuilder结合setState实现基础逻辑,复杂场景可使用Provider、Riverpod等状态管理工具优化。
内容的提问来源于stack exchange,提问作者Nahid
相关产品推荐
相关产品推荐

