はじめに
この記事は「NTTテクノクロス Advent Calendar 2024」の5日目の記事です。
こんにちは!NTTテクノクロスの沼田です。
現在、flutterで地図アプリの開発をしています。
今回は、実際に案件で使用しているライブラリや、苦労している点を踏まえ、flutter_mapをご紹介いたします。
flutter_map とは
・Flutterで地図を表示するためのライブラリ
・オープンソースのMAP-API(OSMなど)を使うのであれば基本無料で作成可能
・カスタマイズが豊富
こんな人におすすめ
・費用を抑えたい
・細かくカスタマイズしたい(詳細は後述)
・独自の地図データを使用したアプリを作成したい(詳細は後述)
flutter_mapで何ができるのか
地図の基本的な機能はもちろん、拡張も豊富なので、大抵のことは出来ます。
(GoogleMapのようなアプリが作成できます)
今回は、細かいカスタマイズ方法までご紹介します。
◾️ 地図の表示
オンライン地図、オフライン地図どちらの表示も可能。任意の地図タイル画像の表示も可能です。
例 )オフライン地図表示の例
asset配下に置いた地図タイル画像を使用している公式サンプル
bundled_offline_map.dart
◾️ 地図操作の制御
回転不可、操作可能範囲を設定といった基本的な制御は、 InteractionOptionsを使用します。
自分好みに細かい制御をカスタマイズする場合は、 InteractionOptionsを使用します
★ GoogleMapのように「拡大縮小時のみ回転なし」にしたい
以下設定で適用できます。
interactionOptions: const InteractionOptions(
rotationWinGestures:
MultiFingerGesture.pinchZoom | MultiFingerGesture.rotate,
),
◾️ ポリゴンやラインの表示
Polygon Layerを使用
自由にポリゴン表示ができます。
Polyline Layerを使用
画像はプロパティで点線にしています。点線の感覚をもう少し広げたかったのですが、現在間隔を設定できるプロパティは用意されていませんでした。
◾️ 地図マーカーの表示
Marker Layerを使用
画像やButtonをマーカーに設定できます。
画像のマーカーは、マーカーのアイコンと、テキストをColumnで並べて表示しています。
★ 指定した箇所を中心にマーカーを回転させたい場合
例えば、地図に以下の画像のようなマーカーを表示し、地図を回転させたとします。
デフォルトの設定だと、画像の中央を回転軸としてマーカーも回転するので、本来回って欲しい座標軸でマーカーが回転されず、マーカーの表示がずれてしまいます。
ピンの先っぽを回転軸としたい場合、alignmentのbottomCenterなどを使って好みの場所に座標軸を設定することで解消できます。
別ライブラリとの組み合わせで出来ること
◾️ 現在地・方向の表示
flutter_map_location_marker パッケージを使用
画像のように現在地を表示することが出来ます。現在地アイコンは自由にカスタマイズ可能です。
デフォルトでは位置情報を扱うGeolocatorパッケージと、端末の向きを取得するflutter_compassパッケージが使用されており、それらをもとに現在地が表示されています。
◾️ ヘディングアップ・ノースアップ
同じく、flutter_map_location_marker パッケージを使用
GoogleMapの右下にある現在地中心ボタンと同様の実装が可能で、端末の向きに従い、地図も回転させるといった制御が可能です。
◾️ アニメーションの追加
flutter_map_animationsパッケージを使用
flutter_mapのデフォルトのアニメーションは、カクカクした動きしか対応していません。本パッケージによって、滑らかなアニメーションをつけることが可能です
◾️ マーカーピンのクラスタリング
flutter_map_marker_clusterパッケージを使用
【iOSのみ】 flutter_map_location_markerについて
現在地の表示を行っているflutter_map_location_markerですが、
同じ画面でGeolocatorパッケージを使用して現在地の更新(getPositionStream)、取得(getCurrentPosition)を行うと、位置情報が更新されなかったり、現在地のちらつきが発生するといった事象がありました。
結果、Geolocatorではなく、Locationパッケージを使用するよう変更したことで対処しましたが、現在地を表示するCurrentLocationLayerが正常に描画されるかは、確認を行うのがいいと思いました。
記録用に、最終的にうまく描画できた時のCurrentLocationLayer
CurrentLocationLayer(
positionStream: const LocationMarkerDataStreamFactory()
.fromGeolocatorPositionStream(),
.asBroadcastStream(),
....
)
iOSは位置情報に注意
(flutter_mapとは直接関係ない話になります)
flutterで位置情報を扱うパッケージ(Geolocator、Locationなど)を使用する際は、Androidで問題なく動いても、iOS実機での検証は必須です。
連続で現在地を取得しない
連続で現在地取得を行うと、2回目以降取得できなくなることが多くあります。
こちらはissueに上がっています。(Geolocator)
https://github.com/Baseflow/flutter-geolocator/issues/1193
対策
1、位置情報の取得方法を変更する
getPositionStreamを使用して位置の更新を取得する実装に変更することで、頻繁にCurrentLocationを実行しないようにする。
2、最後に取得された既知の場所を取得するように変更する
getLastKnownPositionを使用して最後に取得した位置情報を返す実装に変更する。
インターバルを設けて、指定秒数以内に取得できない場合はgetLastKnownPositionを使う、といった実装になるかと思います。
開発中のアプリでは、信憑性の高い現在地が必要だったので1を採用しました。
最後に
ざっとflutter_mapの紹介をしましたが、やろうと思えばGoogleMapと似たようなアプリの作成は可能です。
無料で簡単に使えるので、お試しで使いたい方は是非公式を参考にしてみてください。
繰り返しにはなりますが、位置情報周りの実装はAndroidとiOSそれぞれの実機で、こまめに、検証を行いながら開発することをおすすめします。