Esta é uma série de artigos que apresenta funcionalidades úteis para o desenvolvimento de aplicativos de mapas com Flutter. Desta vez, focaremos na exibição de mapas offline. Implementaremos a funcionalidade de baixar mapas no dispositivo e exibi-los offline. Neste artigo,Flutter SDK de mapa para (ArcGIS Maps SDK for Flutter) será usado para mostrar como implementar essa funcionalidade.
O código de exemplo está disponível em GitHub , então se quiser conferir imediatamente, faça o download. As instruções para executar o aplicativo estão descritas no README . Para executar o exemplo, é necessário obter umachave API (gratuita) . Para saber como instalar o SDK e exibir o mapa, consulte o artigo "Flutter で地図アプリを作成してみよう!". Neste artigo, focaremos na funcionalidade da exibição do mapa offline.
Mapas offline (camada vector tile) criação
Desta vez, criaremos uma funcionalidade para baixar dados da área desejada do mapa exibido no aplicativo. Primeiro, criaremos uma camada vector tile compatível com download para uso offline.Camada vector tile
1. Faça login no ArcGIS Online ArcGIS Online ou na conta do ArcGIS Location Platform. Se você não tiver uma conta, pode criar uma gratuitamente seguindo as instruções aquiの手順から無償で作成できます。
2. Abra o link aquiのリンクを開き、ArcGIS Basemap Styles , que são camadas vector tile.
3. Escolha um item cujo nome contenha “(for Developers)”, como “World Street Map (mapa rodoviário)” ou “World Topographic Map (mapa topográfico)”. Clique no nome do item selecionado e depois clique em [Mostrar detalhes] no canto inferior esquerdo.[Mostrar detalhes].
4. Clique em [Editar no Vector Tile Style Editor] no canto superior direito.[Vector Tile Style Editor]Vector Tile Style Editor, permite personalizar a aparência original do mapa conforme a finalidade. Para mais detalhes sobre o editor, consulte também o artigo aquiの記事もご覧ください。
5. 左上の [クイック編集] をクリックして、[言語] の設定を英語から日本語に変更します。
6. [名前を付けて保存] をクリックして、[名前を付けてスタイルを保存] 画面を表示します。
7. タイトルに適当な名前を記入し、[次のレイヤーと共有:] を「すべてのユーザー (パブリック)」に変更して、[スタイルの保存] をクリックします。
8. Web ブラウザーに表示されている URL の英数字の部分が、このベクター タイル レイヤー スタイルの ID です。この ID を後の手順で使用します。
オフラインマップの表示機能の実装
続いて、オフラインマップを表示するアプリを開発していきます。
1. 「Flutter で地図アプリを作成してみよう!」のブログ記事の手順 6 で、マップビュー コントローラーに作成したマップを設定してマップの表示までできることを確認します。
パッケージの追加
2. デバイス内のパスの取得に path_provider パッケージを使用するため、pubspec.yaml の dependencies セクションにパッケージを追加します。
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
arcgis_maps: ^200.8.0+4672
# 追加
path_provider: ^2.1.5
3. lib/main.dart を開き、既に書かれているインポート行の後に、下記のコードを追加して、この後の処理に必要なパッケージをインポートします。
import 'package:path_provider/path_provider.dart';
import 'dart:io';
変数の追加
4. _MyHomePageState クラスの最初に、使用する変数を追加します。
// オンライン時に表示するマップ オブジェクト格納用
ArcGISMap? _onlineMap;
// ベクター タイルを表示するためのレイヤー オブジェクト
ArcGISVectorTiledLayer? _vectorTiledLayer;
// ベクター タイルをダウンロードする際に使用するジョブ
ExportVectorTilesJob? _exportVectorTilesJob;
// ローディングバー (LinearProgressIndicator) の表示フラグ
bool _loading = false;
UI の作成
5. オンラインマップとオフラインマップの表示を切り替えるボタンを追加します。build Widget の中に既にある Expanded ウィジェットの下に、下記を追加します。
children: [
Expanded(
child: Stack(children: [
ArcGISMapView(
・・・省略・・・
])),
// 追加
Row(
mainAxisAlignment: MainAxisAlignment.center,
// オンラインマップとオフラインマップの表示を切り替えるボタンを追加します。
children: [
ElevatedButton(
onPressed: takeOnline,
child: const Text('オンライン表示'),
),
SizedBox(width: 5.0),
ElevatedButton(
onPressed: takeOffline,
child: const Text('オフラインマップ作成'),
),
]
)
6. マップ上にインジケーター (LinearProgressIndicator) を表示するようにコードを変更します。
// 変更前
child: ArcGISMapView(
controllerProvider: () => _mapViewController,
onMapViewReady: _onMapViewReady,
),
// 変更後
child: Stack(children: [
ArcGISMapView(
controllerProvider: () => _mapViewController,
onMapViewReady: _onMapViewReady),
Visibility(
visible: _loading,
child: SizedBox.expand(
child: Container(
margin: EdgeInsets.all(20),
child: Center(
child: LinearProgressIndicator(
minHeight: 20,
),
),
),
),
),
])
ダウンロード機能の実装
7. ベースマップを作成する既存のコードを、「オフラインマップ (ベクター タイル レイヤー) の作成」で作成したベクター タイル レイヤーを表示するベースマップに変更します。PortalItem.withPortalAndItemId コンストラクターの itemId には、「オフラインマップ (ベクター タイル レイヤー) の作成」の手順.8 で表示された ID を設定します。
// 変更前
// ベースマップのラベルを日本語表記にするためのパラメーターを設定します。
final bsp = BasemapStyleParameters();
bsp.specificLanguage = "ja";
final basemap = Basemap.withStyle(BasemapStyle.arcGISStreets, parameters: bsp);
// 変更後
// ポータルのアイテム ID からベクター タイル レイヤーを作成します。
final portal = Portal(
Uri.parse('https://www.arcgis.com'),
);
final portalItem = PortalItem.withPortalAndItemId(
portal: portal, itemId: "aa3f471a985641e094549ef472adec18");
_vectorTiledLayer = ArcGISVectorTiledLayer.withItem(portalItem);
// ベクター タイル レイヤーをベースマップのレイヤーにしてマップを作成します。
final basemap = Basemap.withBaseLayer(_vectorTiledLayer,);
8. ここからは、マップをダウンロードする処理を実装していきます。「オフラインマップ作成」ボタンをタップした時に実行される takeOffline 関数 (ElevatedButton の onPressed プロパティに設定) を作成します。
// 「オフラインマップ作成」ボタンを選択したときの処理
void takeOffline() async {
if (_mapViewController.arcGISMap != _onlineMap) return;
}
9. takeOffline 関数内にコードを追加していきます。まず、処理中を示すためのインジケーターを表示します。
// インジケーターを表示します。
setState(() => _loading = true);
10. ベクター タイルをダウンロードするための、ExportVectorTilesTask を作成します。このタスクは、ベクター タイルのソースデータ (.vtpk ファイル) とスタイル リソースをローカルにダウンロードするためのタスクです。
// ダウンロードしたベクター タイルを保存するためのディレクトリを準備します。
final directory = await getApplicationDocumentsDirectory();
final resourceDirectory = Directory(
'${directory.path}${Platform.pathSeparator}offline',
);
if (resourceDirectory.existsSync()) {
resourceDirectory.deleteSync(recursive: true);
}
resourceDirectory.createSync(recursive: true);
final resourceDirectoryPath = resourceDirectory.path;
final vtpkFile = File(
'$resourceDirectoryPath${Platform.pathSeparator}basemap.vtpk',
);
// ベクター タイル レイヤーの URL をパラメーターに設定してタスクを作成・ロードします。
final vectorTilesExportTask =
ExportVectorTilesTask.withUri(_vectorTiledLayer!.uri!);
await vectorTilesExportTask.load();
// 現在のマップの表示範囲を取得します (この範囲のベクター タイルをダウンロードします)。
final downloadArea = _mapViewController.visibleArea!.extent;
// タスク実行時に使用するパラメーターを作成します。
final exportVectorTilesParameters =
await vectorTilesExportTask.createDefaultExportVectorTilesParameters(
areaOfInterest: downloadArea,
maxScale: _mapViewController.scale,
);
// Configura os parâmetros e o destino do download para criar a tarefa de trabalho (ExportVectorTilesJob).
_exportVectorTilesJob =
vectorTilesExportTask.exportVectorTilesWithItemResourceCache(
parameters: exportVectorTilesParameters,
vectorTileCacheUri: vtpkFile.uri,
itemResourceCacheUri: Uri.directory(resourceDirectoryPath),
);
11. Execute a ExportVectorTilesTask para iniciar o processo de download. Para executar a tarefa, execute o método (ExportVectorTilesJob) do trabalho criado pela tarefa. run . Se o trabalho for bem-sucedido, crie um novo mapa offline a partir dos tiles vetoriais baixados.
try {
// Inicie o trabalho e obtenha o resultado.
final result = await _exportVectorTilesJob?.run();
// Se o trabalho for bem-sucedido, obtenha o cache dos tiles vetoriais e o cache dos recursos do item.
final vectorTilesCache = result?.vectorTileCache;
final itemResourceCache = result?.itemResourceCache;
if (vectorTilesCache == null || itemResourceCache == null) {
showErrorDialog('O cache dos tiles vetoriais ou o cache dos recursos do item está inválido');
return;
}
// Crie uma camada de tiles vetoriais a partir dos tiles baixados.
final localVectorTileLayer = ArcGISVectorTiledLayer.withVectorTileCache(
vectorTilesCache,
itemResourceCache: itemResourceCache,
);
// Crie um mapa offline a partir do mapa base que inclui a camada de tiles vetoriais.
_mapViewController.arcGISMap = ArcGISMap.withBasemap(
Basemap.withBaseLayer(
localVectorTileLayer,
),
);
} on ArcGISException catch (e) {
showErrorDialog(e.message);
} finally {
_exportVectorTilesJob = null;
}
12. Por fim, esconda o indicador.
// Esconde o indicador.
setState(() {
_loading = false;
});
13. Em seguida, crie a função para exibir mensagens de erro chamada showErrorDialog .
void showErrorDialog(String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Info', style: Theme.of(context).textTheme.titleMedium),
content: Text(
'Falha ao baixar os tiles vetoriais:\n$message',
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Fechar'),
),
],
),
);
}
14. Crie a função takeOnline , que será executada ao tocar no botão “Exibir Online”. Para alterar o mapa exibido de offline para online, defina a variável ' _mapViewController.arcGISMap ' ' para ' _onlineMap ' .
void takeOnline() {
_mapViewController.arcGISMap = _onlineMap;
}
15. 今の状態では、_onlineMap が空のため、マップの初期作成時に _onlineMap に現在のマップを保存します。_onMapViewReady 関数の最後に下記を追加します。
void _onMapViewReady() {
・・・省略・・・
_mapViewController.arcGISMap = map;
// 追加
// オンラインマップへの切替用に、現在のマップ状態を保存します。
_onlineMap = map;
}
16. 以上でダウンロード機能の実装は完了です。ビルドして任意の場所をダウンロードしてみてください (現在のマップの表示範囲のデータがダウンロードされます) 。ダウンロードが完了すると、その範囲のデータしか表示されていないことが分かります。
まとめ
本記事では、オフラインマップの表示機能を実装しました。ExportVectorTilesTask や ExportVectorTilesJob では、マップを任意のスケールでダウンロードしたり、ダウンロード処理を途中で停止/再開したり、処理の進捗状況を確認したりといった設定も可能です。 また、今回実装したようにベースマップをインターネットを介してダウンロードする方法以外にも、事前にパッケージ ファイルを作成しておき、そのローカル データをアプリで表示することも可能です。利用可能なオフライン機能については、こちらのページもご覧ください。
関連リンク