This is a blog series introducing features useful for developing map apps with Flutter.In mobile map apps, the feature to display a map linked to the device's current location is commonly discussed. In this article, we introduce how to implement this feature using the Flutter map SDK (ArcGIS Maps SDK for Flutter).
Sample code is available on GitHub, so if you want to check it immediately, please download it. Instructions for running the app are described in README. To run the sample, you need to obtain an API key (free).
For instructions from introducing the map SDK to displaying maps, please see the blog article "Flutter Let's Create a Map App!". This article focuses on the feature of map display linked to the current location.
Adding Permissions
To access device location information in your application, you need to add the following permissions. Add each permission to the corresponding file.
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>NSLocationUsageDescription</key>
<string>Permission to use location services is required to access location information.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Permission to use location services is required to access location information.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Permission to use location services is required to access location information.</string>
The string set in Info.plist's string tag is displayed as a confirmation message when users access location information. Please set any message you prefer.
Implementing Current Location Display Feature
The feature to display the current location on the map uses the LocationDisplay class. LocationDisplay obtains the current location from the data source specified by LocationDataSource, and displays a symbol of the current location on the map. When the current location updates, the symbol's position on the map automatically updates as well. Additionally, you can automatically move or rotate the map when current location, heading, or course updates.
1. After setting up and displaying the created map in the map view controller as described in step 6 of the blog article "Flutter Let's Create a Map App!"," set the data source for location information on _mapViewController's LocationDisplay.
// Set the created map in the map view controller.
_mapViewController.arcGISMap = map;
// Configure to display current location from system location services on the map.
_mapViewController.locationDisplay.dataSource = SystemLocationDataSource();
SystemLocationDataSourceSimulatedLocationDataSource. SystemLocationDataSource uses device system location information. SimulatedLocationDataSource can use simulated device locations for testing. You can also use a collection of current locations (ArcGISLocation) or specify speed and line with setLocationsWithPolyline method to move along a line.
2. Next, configure how to display/move the map when location updates using AutoPanMode を使用して設定します。
// AutoPanMode を Recenter モードに設定します。
_mapViewController.locationDisplay.autoPanMode = LocationDisplayAutoPanMode.recenter;
AutoPanMode は、徒歩や車両でのナビゲーション用に以下の表示モードが用意されています。アプリの用途に応じて適切なモードを選択/切替えて利用できます。
- Recenter: 現在地が wanderExtentFactor で設定された範囲外に移動したときに、現在地を再度画面の中心に表示するようにマップが自動で移動します。wanderExtentFactor には、0 から 1 の間の値を設定します。0 の場合は、現在地が更新される度にマップが移動します。1 の場合は、現在地が現在のマップの表示範囲の端に達したときにマップが移動します。
- Navigation: 現在地が常に画面の下部に表示されるようにマップが自動で移動します。また、進行方向が常にデバイス上端を向くように、進行方向に基づいて自動でマップが回転します。車両での移動を想定したモードです。
- Compass Navigation: 現在地が常に画面の中心に表示されるようにマップが自動で移動します。また、向いている方向が常にデバイス上端を向くように、向きに基づいて自動でマップが回転します。徒歩での移動を想定したモードです。
- Off: 現在地のみが更新され、地図は自動で移動しません。
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'), // Zoom the map so the current location is centered
),
DropdownMenuItem(
value: LocationDisplayAutoPanMode.navigation,
child: Text(
'Navigation'), // Always show the current location at the bottom of the map and rotate the map according to the device's direction
),
DropdownMenuItem(
value: LocationDisplayAutoPanMode.compassNavigation,
child: Text(
'Compass'), // Always show the current location at the center of the map and rotate the map according to the device's facing direction
),
],
),
],
),
],
),
);
}
5. Add the locationSettings widget created in the previous step to the Expanded containing ArcGISMapView.
children: [
Expanded(
// Add the map view to the widget tree and set up the controller.
child: ArcGISMapView(
controllerProvider: () => _mapViewController,
onMapViewReady: _onMapViewReady,
),
),
// Add the locationSettings widget below the map screen.
locationSettings(context),
],
6. At the beginning of the _MyHomePageState class, create a _isLocationStarted variable to track the state of LocationDisplay. In the locationSettings widget, turn on the "Show Location" switch when LocationDisplay is started (start) and turn off the switch when LocationDisplay is stopped (stop).
bool _isLocationStarted = true;
7. Finally, open lib/main.dart and add the following code after the existing import lines to import necessary packages for processing.
import 'dart:math';
With this, the UI for starting/stopping location acquisition and switching AutoPanMode is complete. Launch the app and try switching AutoPanMode to see how each mode behaves.
Summary
In this article, we implemented a feature that displays a map linked to the device's current location. The LocationDisplay class also allows settings not covered here, such as changing the location symbol, zoom scale when initially displaying current location, and display position of current location in Navigation mode. Please customize it in your own style and try it out.
Related Links