Esta é uma série de artigos de blog que apresenta funcionalidades úteis para o desenvolvimento de aplicativos de mapas com Flutter.Em aplicativos móveis de mapas, a funcionalidade de exibir o mapa sincronizado com a localização atual do dispositivo é bastante comum. Neste artigo, apresentamos como implementar essa funcionalidade usando o SDK de mapas para Flutter (ArcGIS Maps SDK for Flutter).
O código de exemplo está disponível no GitHub, então, se quiser conferir imediatamente, faça o download. As instruções para executar o aplicativo estão no arquivo README. Para executar o exemplo, é necessário obter uma chave API (gratuita).
Para saber como introduzir o SDK de mapas e exibir o mapa, consulte o artigo do blog "Flutter で地図アプリを作成してみよう!". Este artigo foca na funcionalidade de exibir o mapa sincronizado com a localização atual.
Adicionando permissões
Para acessar a localização do dispositivo no aplicativo, é necessário adicionar as permissões abaixo. Adicione cada permissão nos arquivos correspondentes.
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>Para acessar a localização, é necessário permitir o uso da localização pelo aplicativo.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Para acessar a localização, é necessário permitir o uso da localização pelo aplicativo.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Para acessar a localização, é necessário permitir o uso da localização pelo aplicativo.</string>
A string definida na tag string do Info.plist será exibida ao usuário para confirmar quando ele acessar a localização. Defina uma mensagem apropriada.
Implementando a funcionalidade de exibir a localização atual
Para exibir a localização atual no mapa, usamos a classe LocationDisplay. LocationDisplay obtém a localização atual da fonte de dados especificada em LocationDataSource, e exibe um símbolo da localização atual no mapa. Quando a localização atual é atualizada, a posição do símbolo no mapa também é atualizada automaticamente. Além disso, é possível mover ou girar automaticamente o mapa quando a localização atual, orientação ou direção são atualizadas.
1. Após configurar e exibir o mapa no controlador do MapView conforme passo 6 do artigo "Flutter で地図アプリを作成してみよう!", defina a fonte dos dados que será usada para obter a localização no LocationDisplay do _mapViewController.
・・・
// Define o mapa criado no controlador do MapView.
_mapViewController.arcGISMap = map;
// Adicional
// Configura para exibir a posição atual usando os serviços de localização do sistema.
_mapViewController.locationDisplay.dataSource = SystemLocationDataSource();
Você pode definir como fonte dos dados SystemLocationDataSource ou SimulatedLocationDataSource を設定できます。SystemLocationDataSource はデバイス システムで使用される位置情報を使用します。SimulatedLocationDataSource はテスト用にシミュレートされたデバイスの位置情報を使用できます。現在地 (ArcGISLocation) のコレクションを使用するか、setLocationsWithPolyline メソッドで移動速度とラインを指定して、ラインに沿って現在地を移動させることもできます。
2. 続いて、位置情報が更新されたときにマップをどのように表示/移動させるかを 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('Recentralizar'), // Zoom no mapa para que a posição atual fique no centro
),
DropdownMenuItem(
value: LocationDisplayAutoPanMode.navigation,
child: Text(
'Navegação'), // Exibe a posição atual sempre na parte inferior do mapa e gira o mapa conforme a direção do dispositivo
),
DropdownMenuItem(
value: LocationDisplayAutoPanMode.compassNavigation,
child: Text(
'Compass'), // Exibe a posição atual sempre no centro do mapa e gira o mapa conforme a direção para onde o dispositivo está apontando
),
],
),
],
),
],
),
);
}
5. Adicione o widget locationSettings criado na etapa anterior dentro do Expanded que contém o ArcGISMapView.
children: [
Expanded(
// Adiciona o MapView na árvore de widgets e configura o controlador.
child: ArcGISMapView(
controllerProvider: () => _mapViewController,
onMapViewReady: _onMapViewReady,
),
),
// Adiciona o widget locationSettings abaixo da tela do mapa.
locationSettings(context),
],
6. No início da classe _MyHomePageState, crie a variável _isLocationStarted para controlar o estado do LocationDisplay. No widget locationSettings, quando o LocationDisplay for iniciado (start), ative o switch "Exibir localização"; quando o LocationDisplay for parado (stop), desative esse switch.
bool _isLocationStarted = true;
7. Por fim, abra lib/main.dart e adicione o código abaixo após as linhas de importação já existentes para importar os pacotes necessários para o funcionamento.
import 'dart:math';
Com isso, a interface para iniciar/parar a obtenção da localização e alternar o AutoPanMode está completa. Execute o aplicativo e alterne entre os modos AutoPanMode para verificar o comportamento de cada um.
Resumo
Neste artigo, implementamos uma funcionalidade que exibe um mapa sincronizado com a localização atual do dispositivo. A classe LocationDisplay permite configurar várias opções não abordadas aqui, como alterar o símbolo da localização atual, definir a escala do mapa ao exibir a localização inicial e ajustar a posição da exibição da localização no modo Navigation. Experimente personalizar seu estilo de exibição conforme preferir.
Links relacionados