You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Google Maps如何同时显示所有标记的信息窗口?

在Flutter Google Maps中同时显示所有标记的信息窗口

默认情况下,Flutter的Google Maps插件不支持同时显示多个Marker的Info Window——插件本身的设计就是每次只能展示一个Info Window,当你通过循环调用marker.showInfoWindow()时,后续的调用会自动关闭之前打开的窗口,最终只保留最后一个。

要实现同时显示所有信息窗口的效果,你需要放弃使用Marker自带的Info Window,改用自定义Info Window组件,将其作为独立Widget叠加在地图上方,具体实现如下:

实现思路

  1. 用Stack组件将Google Maps和自定义Info Window放在同一层级;
  2. 通过GoogleMapController把每个Marker的经纬度转换为屏幕坐标;
  3. 根据转换后的坐标定位自定义Info Window的位置;
  4. 监听地图相机移动事件(缩放、拖动),实时更新Info Window的位置,保证坐标匹配。

代码示例

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class MultiInfoWindowMap extends StatefulWidget {
  const MultiInfoWindowMap({super.key});

  @override
  State<MultiInfoWindowMap> createState() => _MultiInfoWindowMapState();
}

class _MultiInfoWindowMapState extends State<MultiInfoWindowMap> {
  late GoogleMapController _mapController;
  final List<Marker> _markers = [
    Marker(
      markerId: const MarkerId('marker1'),
      position: const LatLng(37.7749, -122.4194),
    ),
    Marker(
      markerId: const MarkerId('marker2'),
      position: const LatLng(37.7895, -122.401),
    ),
    // 可添加更多标记
  ];
  final Map<MarkerId, Offset> _markerScreenOffsets = {};

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        GoogleMap(
          initialCameraPosition: const CameraPosition(
            target: LatLng(37.7749, -122.4194),
            zoom: 12,
          ),
          markers: Set.of(_markers),
          onMapCreated: (controller) {
            _mapController = controller;
            _updateMarkerScreenPositions();
          },
          onCameraMove: (_) => _updateMarkerScreenPositions(),
        ),
        // 渲染所有自定义Info Window
        ..._markers.map((marker) {
          final offset = _markerScreenOffsets[marker.markerId];
          if (offset == null) return const SizedBox.shrink();
          // 调整偏移让窗口显示在标记上方
          final adjustedOffset = Offset(offset.dx, offset.dy - 70);
          return Positioned(
            left: adjustedOffset.dx,
            top: adjustedOffset.dy,
            child: _CustomInfoWindow(
              title: '标记 ${marker.markerId.value}',
              snippet: '自定义信息窗口内容',
            ),
          );
        }),
      ],
    );
  }

  // 计算标记对应的屏幕坐标
  void _updateMarkerScreenPositions() async {
    final offsets = <MarkerId, Offset>{};
    for (final marker in _markers) {
      final screenCoord = await _mapController.getScreenCoordinate(marker.position);
      offsets[marker.markerId] = Offset(
        screenCoord.x.toDouble(),
        screenCoord.y.toDouble(),
      );
    }
    if (mounted) {
      setState(() => _markerScreenOffsets.addAll(offsets));
    }
  }
}

// 自定义Info Window样式组件
class _CustomInfoWindow extends StatelessWidget {
  final String title;
  final String snippet;

  const _CustomInfoWindow({required this.title, required this.snippet});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.5),
            blurRadius: 4,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
          const SizedBox(height: 4),
          Text(snippet, style: const TextStyle(fontSize: 12)),
        ],
      ),
    );
  }
}

注意事项

  • 自定义Info Window的样式可完全自定义,适配不同UI需求;
  • 标记数量过多时需注意性能,避免大量Widget渲染导致卡顿;
  • 如需给Info Window添加交互(比如点击事件),直接在自定义组件中添加即可。

内容的提问来源于stack exchange,提问作者user9733254

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:35:18