Select to view content in your preferred language

Flutter で地図アプリを作成してみよう!~現在地の表示~

336
0
2 weeks ago
Labels (1)

Flutter で地図アプリを作成してみよう!~現在地の表示~

gcf_flutter

 フォーラムの詳細/参加登録はこちら

 

 

モバイル地図アプリで、デバイスの現在位置と連動してマップを表示する機能はよく話に出てくる機能だと思います。この記事では、Flutter 用の地図 SDK (ArcGIS Maps SDK for Flutter) を使用して、その機能を実装する方法を紹介します。

サンプルコードは  GitHub に公開しているので、すぐに確認したい方は、ダウンロードしてみてください。アプリの実行方法は README に記載しています。サンプルを実行するために、API キーの取得 (無償) が必要になります。

地図 SDK の導入からマップ表示までの方法は「Flutter で地図アプリを作成してみよう!」のブログ記事をご覧ください。この記事では、現在地と連動したマップ表示の機能にフォーカスして紹介します。

 

app.png

パーミッションの追加

アプリケーションでデバイスの位置情報にアクセスするには、以下のパーミッションの追加が必要です。該当ファイルに各パーミッションを追加します。

Android

android/app/src/main/AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

iOS

ios/Runner/Info.plist

<key>NSLocatS_FINE_LOCATION" />ionUsageDescription</key>
<string>位置情報にアクセスするには、アプリへの位置情報の利用の許可が必要です。</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>位置情報にアクセスするには、アプリへの位置情報の利用の許可が必要です。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>位置情報にアクセスするには、アプリへの位置情報の利用の許可が必要です。</string>

Info.plist の string タグに設定する文字列は、ユーザーが位置情報にアクセスする際に確認のために表示される文字列です。任意のメッセージを設定してください。

 

現在地の表示機能の実装

マップに現在地を表示する機能は LocationDisplay クラスを使用します。LocationDisplay は LocationDataSource で指定したデータソースから現在地を取得し、マップ上に現在地のシンボルを表示します。現在地が更新されると、マップ上のシンボルの位置も自動で更新されます。また、現在地、方位、進行方向が更新されたときにマップを自動的に移動や回転させることもできます。

 

1. 「Flutter で地図アプリを作成してみよう!」のブログ記事の手順 6 で、マップビュー コントローラーに作成したマップを設定してマップの表示までできたら、_mapViewController の LocationDisplay に位置情報のソースとなるデータ ソースを設定します。

・・・

// マップビュー コントローラーに作成したマップを設定します。
_mapViewController.arcGISMap = map;

// 追加
// システムの位置情報サービスの現在位置をマップ上に表示するように設定します。
_mapViewController.locationDisplay.dataSource = SystemLocationDataSource();

データ ソースには、SystemLocationDataSource と SimulatedLocationDataSource を設定できます。SystemLocationDataSource はデバイス システムで使用される位置情報を使用します。SimulatedLocationDataSource はテスト用にシミュレートされたデバイスの位置情報を使用できます。現在地 (ArcGISLocation) のコレクションを使用するか、setLocationsWithPolyline メソッドで移動速度とラインを指定して、ラインに沿って現在地を移動させることもできます。

 

2. 続いて、位置情報が更新されたときにマップをどのように表示/移動させるかを AutoPanMode を使用して設定します。

 // AutoPanMode を Recenter モードに設定します。
 _mapViewController.locationDisplay.autoPanMode = LocationDisplayAutoPanMode.recenter;

AutoPanMode は、徒歩や車両でのナビゲーション用に以下の表示モードが用意されています。アプリの用途に応じて適切なモードを選択/切替えて利用できます。

    • Recenter: 現在地が wanderExtentFactor で設定された範囲外に移動したときに、現在地を再度画面の中心に表示するようにマップが自動で移動します。wanderExtentFactor には、0 から 1 の間の値を設定します。0 の場合は、現在地が更新される度にマップが移動します。1 の場合は、現在地が現在のマップの表示範囲の端に達したときにマップが移動します。

recenter.gif

 

    • Navigation: 現在地が常に画面の下部に表示されるようにマップが自動で移動します。また、進行方向が常にデバイス上端を向くように、進行方向に基づいて自動でマップが回転します。車両での移動を想定したモードです。

navigation.gif

 

    • Compass Navigation: 現在地が常に画面の中心に表示されるようにマップが自動で移動します。また、向いている方向が常にデバイス上端を向くように、向きに基づいて自動でマップが回転します。徒歩での移動を想定したモードです。

compass.gif

 

    • Off: 現在地のみが更新され、地図は自動で移動しません。

off.gif

 

3. 位置情報の取得を開始するための準備ができたので LocationDisplay の start メソッドを呼び出します。

// 位置情報の取得を開始します(これにより、ユーザーに許可を求めるプロンプトが表示されます)。
try {
  await _mapViewController.locationDisplay.dataSource.start();
} on ArcGISException catch (e) {
  if (mounted) {
    showDialog(
      context: context,
      builder: (_) => AlertDialog(content: Text(e.message)),
    );
  }
}

非同期に関するエラーが発生したら、_onMapViewReady 関数に async を付けて、下記のように変更します。

Future<void> _onMapViewReady() async {

これで、デバイスが現在地を取得できる場合に、現在地を示す青いシンボルがマップの中心に表示されるはずです。

 

4. 続いて、位置情報の取得の開始/停止と AutoPanMode を切り替える UI を実装します。まず、これらの UI を含む locationSettings ウィジェットを作成します。

Widget locationSettings(BuildContext context) {
    return Container(
        padding: EdgeInsets.fromLTRB(
            20.0,
            20.0,
            20.0,
            max(
                20.0,
                View.of(context).viewPadding.bottom / View.of(context).devicePixelRatio,
            ),
        ),
        child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
                Row(
                    children: [
                        Text(
                            '表示設定',
                            style: Theme.of(context).textTheme.titleLarge,
                        ),
                        const Spacer(),
                    ],
                ),
                Row(
                    children: [
                        const Text('ロケーションの表示'),
                        const Spacer(),
                        // 位置情報の取得を開始および停止するためのスイッチです。
                        Switch(
                            value: _isLocationStarted,
                            onChanged: (value) {
                                setState(() {
                                    if (_mapViewController.locationDisplay.dataSource.status == LocationDataSourceStatus.started) {
                                        _mapViewController.locationDisplay.stop();
                                        _isLocationStarted = false;
                                    } else {
                                        _mapViewController.locationDisplay.start();
                                        _isLocationStarted = true;
                                    }
                                });
                            },
                        ),
                    ],
                ),
                Row(
                    children: [
                        const Text('Auto-Pan モード'),
                        const Spacer(),
                        // AutoPanMode を選択するためのドロップダウン ボタンです。
                        DropdownButton(
                            value: _mapViewController.locationDisplay.autoPanMode,
                            onChanged: (value) {
                                setState(() {
                                    _mapViewController.locationDisplay.autoPanMode = value!;
                                });
                            },
                            items: const [
                                DropdownMenuItem(
                                    value: LocationDisplayAutoPanMode.off,
                                    child: Text('Off'), // 現在位置のシンボルをマップ上に表示するのみ
                                ),
                                DropdownMenuItem(
                                    value: LocationDisplayAutoPanMode.recenter,
                                    child: Text('Recenter'), // 現在位置が中心になるようにマップをズーム
                                ),
                                DropdownMenuItem(
                                    value: LocationDisplayAutoPanMode.navigation,
                                    child: Text(
                                        'Navigation'), // 現在位置を常にマップの下部に表示して、端末の進行方向によってマップを回転
                                ),
                                DropdownMenuItem(
                                    value: LocationDisplayAutoPanMode.compassNavigation,
                                    child: Text(
                                        'Compass'), // 現在位置を常にマップの中心に表示して、端末の向いている方向によってマップを回転
                                ),
                            ],
                        ),
                    ],
                ),
            ],
        ),
    );
}

 

5. ArcGISMapView がある Expanded に、前の手順で作成した locationSettings ウィジェットを追加します。

children: [
    Expanded(
        // ウィジェット ツリーにマップビューを追加し、コントローラーを設定します。
        child: ArcGISMapView(
            controllerProvider: () => _mapViewController,
            onMapViewReady: _onMapViewReady,
        ),
    ),
    // マップ画面の下に locationSettings ウィジェットを追加します。
    locationSettings(context),
],

 

6. 最後に _MyHomePageState クラスの最初で、LocationDisplay の状態判別用の _isLocationStarted 変数を作成します。locationSettings ウィジェットでは、LocationDisplay が開始 (start) されたら「ロケーションの表示」スイッチをオンにし、LocationDisplay が停止 (stop) されたら「ロケーションの表示」スイッチをオフにします。

bool _isLocationStarted = true;

以上で、位置情報の取得の開始/停止と AutoPanMode を切り替える UI は完成です。実際にアプリを起動して AutoPanMode を切り替え、各モードの動きを確認してみてください。

 

ui.png

 

まとめ

本記事では、デバイスの現在位置と連動してマップを表示する機能を実装しました。LocationDisplay クラスでは、現在地シンボルの変更や現在地の初期表示時にズームするマップのスケール、Navigation モード時の現在地の表示位置等、この記事では紹介していない設定も行えます。ぜひ、自分なりの表示スタイルにカスタマイズしてお試しください。

 

フォーラムのご案内

5月28日~30日の日程で、第22回 GIS コミュニティフォーラムが東京ミッドタウン 六本木にて開催されます!28日には Flutter 開発のテクニカルセッションの発表もありますので、ぜひご参加ください!

 

関連リンク

 

Labels (1)
Version history
Last update:
3 weeks ago
Updated by:
Contributors