Flutter地图集群管理插件google_maps_cluster_manager的使用
Flutter 地图集群管理插件 google_maps_cluster_manager
的使用
介绍
google_maps_cluster_manager
是一个用于在 Flutter 中对 Google Maps 上的标记进行聚类管理的插件。它基于 Geohash 算法实现,可以帮助你在地图上高效地管理和显示大量标记。该插件受到了 clustering_google_maps
的启发。
使用方法
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 google_maps_cluster_manager
作为依赖:
dependencies:
google_maps_cluster_manager: ^最新版本号
2. 创建 ClusterItem
类
你的地图项需要实现 ClusterItem
混入,并提供 LatLng location
getter。例如:
class Place with ClusterItem {
final String name;
final LatLng latLng;
Place({required this.name, required this.latLng});
[@override](/user/override)
LatLng get location => latLng;
}
3. 初始化 ClusterManager
接下来,初始化 ClusterManager
实例,并传入你要聚类的项列表、更新标记的方法以及可选的自定义参数:
ClusterManager<Place>(
_items, // 你要聚类的项列表
_updateMarkers, // 当标记更新时调用的方法
markerBuilder: _markerBuilder, // 可选:自定义标记的构建方法
levels: [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], // 可选:配置聚类精度变化的缩放级别
extraPercent: 0.2, // 可选:在可见地图边界外额外渲染 20% 的区域
stopClusteringZoom: 17.0, // 可选:停止聚类的缩放级别
);
4. 设置 mapId
当 GoogleMapController
创建后,你需要通过 setMapId
方法设置 mapId
:
_controller.complete(controller);
_manager.setMapId(controller.mapId);
5. 更新标记
你可以通过 _updateMarkers
方法来更新地图上的标记:
void _updateMarkers(Set<Marker> markers) {
print('Updated ${markers.length} markers');
setState(() {
this.markers = markers;
});
}
6. 自定义标记
你可以通过 markerBuilder
参数来自定义聚类标记的外观。以下是一个简单的示例,展示如何根据聚类中的项数量创建不同的标记图标:
Future<Marker> Function(Cluster<Place>) get _markerBuilder => (cluster) async {
return Marker(
markerId: MarkerId(cluster.getId()),
position: cluster.location,
onTap: () {
print('---- $cluster');
cluster.items.forEach((p) => print(p));
},
icon: await _getMarkerBitmap(cluster.isMultiple ? 125 : 75, text: cluster.isMultiple ? cluster.count.toString() : null),
);
};
Future<BitmapDescriptor> _getMarkerBitmap(int size, {String? text}) async {
if (kIsWeb) size = (size / 2).floor();
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint1 = Paint()..color = Colors.orange;
final Paint paint2 = Paint()..color = Colors.white;
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, paint2);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.8, paint1);
if (text != null) {
TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
painter.text = TextSpan(
text: text,
style: TextStyle(
fontSize: size / 3,
color: Colors.white,
fontWeight: FontWeight.normal,
),
);
painter.layout();
painter.paint(
canvas,
Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2),
);
}
final img = await pictureRecorder.endRecording().toImage(size, size);
final data = await img.toByteData(format: ImageByteFormat.png) as ByteData;
return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
}
完整示例代码
以下是一个完整的示例应用,展示了如何使用 google_maps_cluster_manager
插件:
import 'dart:async';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cluster Manager Demo',
home: MapSample(),
);
}
}
// Clustering maps
class MapSample extends StatefulWidget {
[@override](/user/override)
State<MapSample> createState() => MapSampleState();
}
class MapSampleState extends State<MapSample> {
late ClusterManager _manager;
Completer<GoogleMapController> _controller = Completer();
Set<Marker> markers = Set();
final CameraPosition _parisCameraPosition =
CameraPosition(target: LatLng(48.856613, 2.352222), zoom: 12.0);
List<Place> items = [
for (int i = 0; i < 10; i++)
Place(
name: 'Place $i',
latLng: LatLng(48.848200 + i * 0.001, 2.319124 + i * 0.001)),
for (int i = 0; i < 10; i++)
Place(
name: 'Restaurant $i',
isClosed: i % 2 == 0,
latLng: LatLng(48.858265 - i * 0.001, 2.350107 + i * 0.001)),
for (int i = 0; i < 10; i++)
Place(
name: 'Bar $i',
latLng: LatLng(48.858265 + i * 0.01, 2.350107 - i * 0.01)),
for (int i = 0; i < 10; i++)
Place(
name: 'Hotel $i',
latLng: LatLng(48.858265 - i * 0.1, 2.350107 - i * 0.01)),
for (int i = 0; i < 10; i++)
Place(
name: 'Test $i',
latLng: LatLng(66.160507 + i * 0.1, -153.369141 + i * 0.1)),
for (int i = 0; i < 10; i++)
Place(
name: 'Test2 $i',
latLng: LatLng(-36.848461 + i * 1, 169.763336 + i * 1)),
];
[@override](/user/override)
void initState() {
_manager = _initClusterManager();
super.initState();
}
ClusterManager _initClusterManager() {
return ClusterManager<Place>(items, _updateMarkers, markerBuilder: _markerBuilder);
}
void _updateMarkers(Set<Marker> markers) {
print('Updated ${markers.length} markers');
setState(() {
this.markers = markers;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _parisCameraPosition,
markers: markers,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
_manager.setMapId(controller.mapId);
},
onCameraMove: _manager.onCameraMove,
onCameraIdle: _manager.updateMap,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_manager.setItems([
for (int i = 0; i < 30; i++)
Place(
name: 'New Place ${DateTime.now()} $i',
latLng: LatLng(48.858265 + i * 0.01, 2.350107))
]);
},
child: Icon(Icons.update),
),
);
}
Future<Marker> Function(Cluster<Place>) get _markerBuilder =>
(cluster) async {
return Marker(
markerId: MarkerId(cluster.getId()),
position: cluster.location,
onTap: () {
print('---- $cluster');
cluster.items.forEach((p) => print(p));
},
icon: await _getMarkerBitmap(cluster.isMultiple ? 125 : 75, text: cluster.isMultiple ? cluster.count.toString() : null),
);
};
Future<BitmapDescriptor> _getMarkerBitmap(int size, {String? text}) async {
if (kIsWeb) size = (size / 2).floor();
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint1 = Paint()..color = Colors.orange;
final Paint paint2 = Paint()..color = Colors.white;
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, paint2);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.8, paint1);
if (text != null) {
TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
painter.text = TextSpan(
text: text,
style: TextStyle(
fontSize: size / 3,
color: Colors.white,
fontWeight: FontWeight.normal,
),
);
painter.layout();
painter.paint(
canvas,
Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2),
);
}
final img = await pictureRecorder.endRecording().toImage(size, size);
final data = await img.toByteData(format: ImageByteFormat.png) as ByteData;
return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
}
}
更多关于Flutter地图集群管理插件google_maps_cluster_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地图集群管理插件google_maps_cluster_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用google_maps_cluster_manager
插件来实现地图集群管理的示例代码。这个插件允许你在Google地图上高效地显示大量标记点,通过集群来优化显示。
首先,确保你已经在pubspec.yaml
文件中添加了google_maps_flutter
和google_maps_cluster_manager
依赖:
dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.1.1 # 请检查最新版本号
google_maps_cluster_manager: ^2.1.0 # 请检查最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤来实现地图集群管理:
- 导入必要的包:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
- 定义地图和集群管理器:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MapScreen(),
);
}
}
class MapScreen extends StatefulWidget {
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
late GoogleMapController _mapController;
late ClusterManager<MyMarker> _clusterManager;
@override
void initState() {
super.initState();
_initClusterManager();
}
void _initClusterManager() {
// 初始化地图控制器和集群管理器
_clusterManager = ClusterManager<MyMarker>(
map: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(37.7749, -122.4194),
zoom: 11.0,
),
onMapCreated: (GoogleMapController controller) {
_mapController = controller;
_clusterManager.onMapReady(controller);
},
),
builder: (context, cluster) {
// 自定义集群标记
return BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueHueCyan,
);
},
algorithm: NonHierarchicalDistanceBasedAlgorithm<MyMarker>(
0.01, // 集群半径
),
updateCallback: (markers, clusters) {
// 更新UI或处理集群变化
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Google Maps Cluster Manager'),
),
body: _clusterManager.map,
floatingActionButton: FloatingActionButton(
onPressed: () {
// 添加一些标记点
_addMarkers();
},
tooltip: 'Add Markers',
child: Icon(Icons.add),
),
);
}
void _addMarkers() {
List<MyMarker> markers = [
MyMarker(position: LatLng(37.7749, -122.4194)),
MyMarker(position: LatLng(37.7750, -122.4184)),
MyMarker(position: LatLng(37.7751, -122.4174)),
// 添加更多标记点...
];
_clusterManager.addItems(markers);
}
}
// 自定义标记数据类
class MyMarker {
final LatLng position;
MyMarker({required this.position});
}
- 运行你的应用:
现在,你可以运行你的Flutter应用,并看到一个带有集群功能的Google地图。你可以通过点击浮动按钮来添加标记点,这些标记点会根据集群算法进行聚合。
这个示例展示了如何使用google_maps_cluster_manager
插件来管理大量地图标记点,并通过集群来提高性能和用户体验。你可以根据需求进一步自定义集群的样式、算法以及交互行为。