Google Maps Flutter高级标记与地图样式

移动开发 2026-07-09

我有一个使用Google Maps Flutter的应用,地图样式共有4 种,可以通过程序切换。

  • 浅色模式
  • 不显示兴趣点的浅色模式
  • 深色模式
  • 不显示兴趣点的深色模式

以前,我会使用style属性,并为每种样式准备了4 个不同的JSON字符串来存放数据。

但最近,我尝试迁移到 AdvancedMarkers,因为Google一直提示 Markers 即将被弃用。

为此,我先构建了这个演示,并理解了几件事:

  1. 对于网页端的高级标记,需要在URL上请求markers API

```html

`` 2. 地图需要一个MapId来渲染高级标记,因此它强制使用基于云的mapId样式,且对style属性的任何修改都会被忽略。 3. 无论是mapId还是colorScheme` 属性,在小部件渲染后更改都不会生效,因此它们不像style属性那样允许热切换样式。

综合这些,我所能做的就是在Cloud Console生成两种地图样式:一种包含兴趣点、一种不包含兴趣点,且两者都包含浅色模式和深色模式。

在执行样式的“切换”时,我会改变 mapIdcolorScheme 和小部件的 key,让Flutter认为这是一个新小部件,并从头重新渲染地图。

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

  static const shibuya = CameraPosition(
    bearing: 192.8334901395799,
    target: LatLng(35.6598003, 139.7023894),
    zoom: 15.151926040649414,
  );

  static const cafePosition = LatLng(35.659172, 139.7023894);
  static const clothesShopPosition = LatLng(35.659528, 139.698723);
  static const flutterLogoPosition = LatLng(35.6614027, 139.6983333);

  /// create a new configuration at https://mapstyle.withgoogle.com/

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  MapColorScheme currentColorScheme = MapColorScheme.light;
  Key lightKey = const Key('light_map');
  Key darkKey = const Key('dark_map');
  Key lightKeyPoi = const Key('lightKeyPoi');
  Key darkKeyPoi = const Key('darkKeyPoi');

  Key currentKey = const Key('light_map');
  String mapIdHidePoi = '61e50871c15e139b9779dedd';
  String showPoiMapId = '61e50871c15e139bc69bfab1';
  String currentMapId = '61e50871c15e139b9779dedd';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Row(
            children: [
              ElevatedButton(
                onPressed: () {
                  currentColorScheme = MapColorScheme.dark;
                  currentKey = darkKey;
                  setState(() {});
                },
                child: const Text('Set Dark Mode'),
              ),
              ElevatedButton(
                onPressed: () {
                  currentColorScheme = MapColorScheme.light;
                  currentKey = lightKey;
                  setState(() {});
                },
                child: const Text('Set Light Mode'),
              ),
              ElevatedButton(
                onPressed: () {
                  currentMapId = mapIdHidePoi;
                  currentKey = darkKeyPoi;
                  setState(() {});
                },
                child: const Text('Hide POI'),
              ),
              ElevatedButton(
                onPressed: () {
                  currentMapId = showPoiMapId;
                  currentKey = lightKeyPoi;

                  setState(() {});
                },
                child: const Text('Show POI'),
              ),
            ],
          ),
          Expanded(
            child: GoogleMap(
              mapId: currentMapId,
              key: currentKey,
              initialCameraPosition: MyHomePage.shibuya,
              mapType: MapType.none,
              markers: {
                AdvancedMarker(
                  position: MyHomePage.shibuya.target,
                  markerId: const MarkerId('default_marker'),
                  icon: BitmapDescriptor.defaultMarker,
                ),
              },
              // style: currentMapStyle,
              colorScheme: currentColorScheme,
              markerType: GoogleMapMarkerType.advancedMarker,
            ),
          ),
        ],
      ),
    );
  }
}

这是预期的做法吗?还是有更好的办法?

我这个实现看起来像是过多的权宜之计凑在一起,而且我不明白为什么如果你想升级到 AdvancedMarkers,Google会如此简单地禁用这类做法。

如果有人找到了更好的实现方式,先感谢;如果在 google_maps_flutter 上已经有未解决的问题,也希望知道。

解决方案

在移动端使用 AdvancedMarkers 时,同时改变 KeymapId 可能是当前实现此目标的唯一方式。强制Flutter重建似乎是一种繁重的权宜之计,但这似乎是由原生SDK的限制所决定。

导致此行为的关键原因:

  1. 原生SDKs(Android和 iOS)在初始化时就需要Map ID,并且不支持对正在运行的地图视图进行动态热切换。
  2. colorScheme 属性仅在网页端生效,对移动平台无效。

因此,使用唯一的Key来强制重建并使用不同的Cloud Console地图ID,似乎是正确的移动端架构。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章