📍

[Flutter]google_maps_flutter2.9.0で追加されたクラスタリング機能を触ってみる

2024/12/26に公開

Flutterのgoogle_maps_flutter で、今までライブラリ単独では実装が難しかったクラスタリング機能が追加されたらしいので試してみました!

https://github.com/flutter/packages/pull/4319

対象の読者

この記事で書かないこと

  • google_maps_flutterの使い方
  • マーカーのクラスタリングとは何かについて(公式例がわかりやすいと思います!)

実施の背景

今までFlutterでクラスタリングを実現する時は、google_maps_flutter + google_maps_cluster_managerの組み合わせで行っていました。
この組み合わせに不満はないのですが、少し前からgoogle_maps_flutter側でもクラスタリング対応のPRが上がっており、2.9.0でマージされたので試してみたいと思った次第です。
期待としては、google_maps_cluster_managerを使わずにクラスタリングを実現することで、以下を実現したいと考えました。

  • 公式から提供されたライブラリのみで機能を実現したい
  • google_maps_cluster_managerに依存している部分を脱却したい

検証

実行環境は以下のとおりです。

$ flutter --version
Flutter 3.27.1 • channel stable
Tools • Dart 3.6.0 • DevTools 2.40.2
pubspec.yaml
  google_maps_flutter: ^2.10.0

PRのexampleを参考にしながら実装してみました。
試してみたリポジトリを公開しています。

マップ部分だけ抜き取ったもの
clustering.dart
class ClusteringMap extends StatefulWidget {
  const ClusteringMap({super.key});

  
  State<ClusteringMap> createState() => MapSampleState();
}

class MapSampleState extends State<ClusteringMap> {
  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();

  static const CameraPosition _kTokyo = CameraPosition(
    target: LatLng(35.681236, 139.767125), // Tokyo Station coordinates
    zoom: 14,
  );

  final Set<Marker> _markers = {};

  void _addMarkers() {
    final List<LatLng> positions = [
      LatLng(35.682839, 139.759455), // Marunouchi
      // マーカー群の配列
      // ...
    ];

    for (int i = 0; i < positions.length; i++) {
      _markers.add(
        Marker(
          markerId: MarkerId('marker_$i'),
          position: positions[i],
          infoWindow: InfoWindow(title: 'Marker $i'),
          clusterManagerId: ClusterManagerId('1'),
        ),
      );
    }
  }

  Set<ClusterManager> clusterManagers = {
    ClusterManager(
      clusterManagerId: ClusterManagerId('1'),
      onClusterTap: (Cluster cluster) => print(cluster.count),
    )
  };

  
  void initState() {
    super.initState();
    _addMarkers();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: GoogleMap(
        initialCameraPosition: _kTokyo,
        markers: _markers,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        clusterManagers: clusterManagers,
      ),
    );
  }
}

クラスタリングが想定通り動くところまで実装できました。
マーカーがクラスタリングされる時/解除される時のアニメーションが今までの google_maps_flutter + google_maps_cluster_manager では表現できなかった動きだなと言うのが率直な感想です。
googlemap_cluster

検証して気づいたこと

  • google_maps_cluster_managerを使う場合と、ClusterManagerの作り方に大差はないと感じた
  • ClusterManagerのプロパティはまだclusterManagerId(クラスタリング群を特定するためのID)とonClusterTap(タップ時に呼び出されるコールバック)くらいしかなさそう
    • google_maps_cluster_managerにあるようなマーカーのカスタマイズなどはできなさそう
  • GoogleMapウィジェットのプロパティにclusterManagersが増えている
    • 複数のClusterManager運用もできるということ(サンプルは複数作成していた)
  • MarkerウィジェットのプロパティにclusterManagerIdが増えている
  • 検証結果のGIFを見ても分かるとおり、マーカーが10以上クラスタリングされると10+表記になる

結論

現時点ではgoogle_maps_flutterに追加されたクラスタリング機能では特にクラスタリングマーカーのカスタマイズができないこともあるので、完全にgoogle_maps_cluster_managerの代替まではできないと思いました(そんなことないよ!と言う方いたらコメントいただけると嬉しいです!)。
その一方で、公式ライブラリ一つでできることの強みや、クラスタリング時のアニメーションの表現力の高さは採用したい理由になると思います。
ぜひこれからのバージョンアップにも期待したいですし、そのためにもよりgoogle_maps_flutterのクラスタリングを使い倒してみます!

Discussion