Flutter地图集群管理插件google_maps_cluster_manager_2的使用
Flutter地图集群管理插件google_maps_cluster_manager_2的使用
简介
google_maps_cluster_manager_2
是一个用于在Flutter应用中实现Google Maps上标记点聚合的插件。它基于Geohash算法,能够高效地管理和显示大量地理标记点,并且提供了丰富的自定义选项。
使用方法
依赖配置
首先,在你的 pubspec.yaml
文件中添加 google_maps_cluster_manager
作为依赖:
dependencies:
google_maps_cluster_manager: ^最新版本号
然后执行 flutter pub get
来安装依赖。
定义数据模型
为了让地图上的项目支持聚类,你需要让它们继承或混入 ClusterItem
类,并实现 LatLng location
的 getter 方法:
class Place with ClusterItem {
final String name;
final LatLng latLng;
Place({required this.name, required this.latLng});
@override
LatLng get location => latLng;
}
初始化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, // 设置额外渲染范围的比例
stopClusteringZoom: 17.0 // 停止聚类的缩放级别
);
地图控制器初始化
当 GoogleMapController
创建完成后,需要设置 mapId
:
_controller.complete(controller);
_manager.setMapId(controller.mapId);
自定义标记图标
你可以通过提供 markerBuilder
参数来自定义聚类标记的外观:
static Future<Marker> Function(Cluster) get markerBuilder => (cluster) async {
return Marker(
markerId: MarkerId(cluster.getId()),
position: cluster.location,
onTap: () {
print(cluster.items);
},
icon: await getClusterBitmap(cluster.isMultiple ? 125 : 75, text: cluster.isMultiple ? cluster.count.toString() : null),
);
};
static Future<BitmapDescriptor> getClusterBitmap(int size, {String? text}) async {
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint1 = Paint()..color = Colors.red;
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, 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);
return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
}
完整示例代码
下面是一个完整的示例应用程序,展示了如何将上述所有部分整合在一起:
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cluster Manager Demo',
home: MapSample(),
);
}
}
class MapSample extends StatefulWidget {
@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
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
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());
}
}
class Place with ClusterItem {
final String name;
final LatLng latLng;
final bool isClosed;
Place({required this.name, required this.latLng, this.isClosed = false});
@override
LatLng get location => latLng;
}
这个例子展示了如何使用 google_maps_cluster_manager_2
插件来管理和展示大量的地理标记点。你可以根据自己的需求调整和扩展此代码。
更多关于Flutter地图集群管理插件google_maps_cluster_manager_2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地图集群管理插件google_maps_cluster_manager_2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中使用google_maps_cluster_manager_2
插件的示例代码。这个插件主要用于在Google地图上管理和显示大量的标记点,通过集群(Clustering)功能来提高性能和用户体验。
首先,确保你的pubspec.yaml
文件中包含了对google_maps_flutter
和google_maps_cluster_manager_2
的依赖:
dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.1.1 # 请检查最新版本
google_maps_cluster_manager_2: ^0.5.0 # 请检查最新版本
然后,运行flutter pub get
来安装这些依赖。
接下来,在你的Flutter应用中,你可以按照以下步骤使用google_maps_cluster_manager_2
插件:
- 导入必要的包:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart';
- 定义你的标记数据:
List<MyLocation> generateDummyData() {
List<MyLocation> dummyData = [];
for (int i = 0; i < 1000; i++) {
double lat = 37.7749 + (i % 200) * 0.001;
double lng = -122.4194 + (i % 200) * 0.001;
dummyData.add(MyLocation(id: i, latitude: lat, longitude: lng));
}
return dummyData;
}
class MyLocation {
final int id;
final double latitude;
final double longitude;
MyLocation({required this.id, required this.latitude, required this.longitude});
}
- 创建集群管理器:
class _MyHomePageState extends State<MyHomePage> {
late GoogleMapController _controller;
late ClusterManager<MyLocation> _clusterManager;
@override
void initState() {
super.initState();
_clusterManager = ClusterManager<MyLocation>(
map: _mapController,
markersCreator: (List<MyLocation> locations) {
return locations.map((location) {
return Marker(
markerId: MarkerId(location.id.toString()),
position: LatLng(location.latitude, location.longitude),
);
}).toList();
},
updateCallback: (List<Marker> markers) {
setState(() {
_markers = markers;
});
},
algorithm: NonHierarchicalDistanceBasedAlgorithm<MyLocation>(
distance: 100, // 集群半径
),
);
_clusterManager.addItems(generateDummyData());
}
@override
void dispose() {
_clusterManager.dispose();
super.dispose();
}
// 其他代码...
}
- 在GoogleMap小部件中使用集群管理器:
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late GoogleMapController _controller;
late ClusterManager<MyLocation> _clusterManager;
late Set<Marker> _markers = Set<Marker>();
final Completer<GoogleMapController> _mapController = Completer();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Google Maps Cluster Manager Demo'),
),
body: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(37.7749, -122.4194),
zoom: 11.0,
),
markers: _markers,
onMapCreated: (GoogleMapController controller) {
_controller = controller;
_mapController.complete(controller);
_clusterManager.setMapId(controller);
},
),
);
}
// 其他代码(如initState和dispose)已在上面的代码段中定义
}
这个示例代码展示了如何创建一个包含大量标记点的Google地图,并使用google_maps_cluster_manager_2
插件来管理这些标记点,通过集群功能提高性能和用户体验。注意,这里的NonHierarchicalDistanceBasedAlgorithm
是集群算法的一种,你可以根据需求选择其他算法,如GridBasedAlgorithm
。
请确保在实际项目中处理异常和错误,并根据需要进行进一步的优化和定制。