Google Maps Flutter高级标记与地图样式
我有一个使用Google Maps Flutter的应用,地图样式共有4 种,可以通过程序切换。
- 浅色模式
- 不显示兴趣点的浅色模式
- 深色模式
- 不显示兴趣点的深色模式
以前,我会使用style属性,并为每种样式准备了4 个不同的JSON字符串来存放数据。
但最近,我尝试迁移到 AdvancedMarkers,因为Google一直提示 Markers 即将被弃用。
为此,我先构建了这个演示,并理解了几件事:
- 对于网页端的高级标记,需要在URL上请求markers API
```html
``
2. 地图需要一个MapId来渲染高级标记,因此它强制使用基于云的mapId样式,且对style属性的任何修改都会被忽略。
3. 无论是mapId还是colorScheme` 属性,在小部件渲染后更改都不会生效,因此它们不像style属性那样允许热切换样式。
综合这些,我所能做的就是在Cloud Console生成两种地图样式:一种包含兴趣点、一种不包含兴趣点,且两者都包含浅色模式和深色模式。
在执行样式的“切换”时,我会改变 mapId、colorScheme 和小部件的 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 时,同时改变 Key 与 mapId 可能是当前实现此目标的唯一方式。强制Flutter重建似乎是一种繁重的权宜之计,但这似乎是由原生SDK的限制所决定。
导致此行为的关键原因:
- 原生SDKs(Android和 iOS)在初始化时就需要Map ID,并且不支持对正在运行的地图视图进行动态热切换。
colorScheme属性仅在网页端生效,对移动平台无效。
因此,使用唯一的Key来强制重建并使用不同的Cloud Console地图ID,似乎是正确的移动端架构。