Flutter地图集群管理插件google_maps_cluster_manager_fork的使用
Flutter 地图集群管理插件 google_maps_cluster_manager_fork 的使用
Flutter 集群管理插件 for Google Maps
这是一个用于在基于 Geohash 的 Google Maps 小部件上进行项目聚类的 Flutter 插件。该项目灵感来源于 clustering_google_maps。
使用方法
要使用此插件,请将 google_maps_cluster_manager
添加为您的 pubspec.yaml
文件中的依赖项。
开始使用
您的地图项目必须使用 ClusterItem
作为混合(或扩展该类)并实现 LatLng location
获取器。
class Place with ClusterItem {
final String name;
final LatLng latLng;
Place({required this.name, required this.latLng});
[@override](/user/override)
LatLng get location => latLng;
}
开始使用集群管理器时,需要初始化一个 ClusterManager
实例。
ClusterManager<Place>(
_items, // 您要在地图上聚类的项目(在这个例子中为 Place 类型)
_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 // 可选:停止聚类的缩放级别,因此它只渲染单个项目的“聚类”
);
当您的 GoogleMapController
创建后,您需要通过 setMapId
方法设置 mapId
:
_manager.setMapId(controller.mapId);
您可以使用 ClusterManager
实例上的 addItem
方法添加新项目到地图上。您也可以通过调用 setItems
方法完全更改地图上的项目。
您可以自定义聚类的图标,通过使用 Future<Marker> Function(Cluster<T extends ClusterItem>) 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());
}
每个聚类(即使是单个项目聚类)都由库作为 Cluster<T extends ClusterItem>
对象呈现。您可以通过使用 isMultiple
变量(或 count
变量)区分单个项目聚类和多个项目聚类。这样,您可以根据聚类类型创建不同的标记图标。
您可以为单个地图创建多个管理器,参见 multiple.dart
示例。
完整基本示例
查看 example
目录以获取完整的示例应用。
完整的基本示例代码
import 'dart:async';
import 'dart:ui';
import 'package:example/place.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager_fork.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(),
);
}
}
// 聚类地图
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 new 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_fork的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地图集群管理插件google_maps_cluster_manager_fork的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用google_maps_cluster_manager_fork
插件来实现地图集群管理的代码示例。这个插件是google_maps_flutter
的扩展,用于在地图上高效地显示大量标记。
1. 添加依赖
首先,在pubspec.yaml
文件中添加google_maps_flutter
和google_maps_cluster_manager_fork
依赖:
dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.1.1 # 请检查最新版本
google_maps_cluster_manager_fork: ^0.4.0 # 请检查最新版本
2. 配置Android和iOS项目
确保你的AndroidManifest.xml
和Info.plist
文件中配置了必要的权限和API密钥。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<!-- 添加网络权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
... >
<!-- 添加Google Maps API密钥 -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_API_KEY"/>
...
</application>
</manifest>
Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>IOSBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>GMSGeocoderAPIKey</key>
<string>YOUR_GOOGLE_MAPS_API_KEY</string>
<key>GMSPlacesAPIKey</key>
<string>YOUR_GOOGLE_MAPS_API_KEY</string>
3. 使用google_maps_cluster_manager_fork
在你的Flutter代码中,使用google_maps_flutter
和google_maps_cluster_manager_fork
来显示集群标记。
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_cluster_manager_fork/google_maps_cluster_manager_fork.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> {
Completer<GoogleMapController> _controller = Completer();
ClusterManager _clusterManager;
@override
void initState() {
super.initState();
_setUpClusterManager();
}
void _setUpClusterManager() {
_clusterManager = ClusterManager(
<Marker>{
// 示例标记数据
Marker(
markerId: MarkerId('1'),
position: LatLng(37.7749, -122.4194),
),
Marker(
markerId: MarkerId('2'),
position: LatLng(37.7750, -122.4195),
),
// 添加更多标记...
},
mapController: _controller.future,
onUpdate: () {
setState(() {});
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Map Cluster Example'),
),
body: Stack(
children: <Widget>[
GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(37.7749, -122.4194),
zoom: 12,
),
markers: Set<Marker>.of(_clusterManager.markers),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
_clusterManager.init(controller);
},
),
// 添加集群标记覆盖层
Positioned.fill(
child: ClusterManagerOverlay(
clusterManager: _clusterManager,
builder: (context, cluster) {
return Marker(
markerId: MarkerId(cluster.id),
position: cluster.position,
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueAzure,
),
infoWindow: InfoWindow(
title: cluster.markers.length.toString(),
snippet: '',
),
);
},
),
),
],
),
);
}
}
说明
- 依赖配置:在
pubspec.yaml
中添加必要的依赖。 - 权限配置:在
AndroidManifest.xml
和Info.plist
中添加必要的权限和API密钥。 - 集群管理:在
_setUpClusterManager
方法中初始化ClusterManager
,并传入标记数据和地图控制器。 - 地图显示:在
GoogleMap
组件中显示标记,并通过ClusterManagerOverlay
添加集群标记覆盖层。
这个示例展示了如何使用google_maps_cluster_manager_fork
插件在Flutter应用中实现地图集群管理。你可以根据实际需求调整标记数据和集群样式。