Flutter地图集群管理插件google_maps_cluster_manager_fork的使用

发布于 1周前 作者 sinazl 来自 Flutter

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

1 回复

更多关于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_fluttergoogle_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.xmlInfo.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_fluttergoogle_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: '',
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

说明

  1. 依赖配置:在pubspec.yaml中添加必要的依赖。
  2. 权限配置:在AndroidManifest.xmlInfo.plist中添加必要的权限和API密钥。
  3. 集群管理:在_setUpClusterManager方法中初始化ClusterManager,并传入标记数据和地图控制器。
  4. 地图显示:在GoogleMap组件中显示标记,并通过ClusterManagerOverlay添加集群标记覆盖层。

这个示例展示了如何使用google_maps_cluster_manager_fork插件在Flutter应用中实现地图集群管理。你可以根据实际需求调整标记数据和集群样式。

回到顶部