Dies ist ein Blogartikel, der Funktionen für die Entwicklung von Karten-Apps mit Flutter in einer Serie vorstellt. Diesmal geht es um die Anzeige von Offline-Karten. Wir implementieren eine Funktion, mit der Karten auf das Gerät heruntergeladen und offline angezeigt werden können. In diesem Artikel wirdFlutter Karten- SDK (ArcGIS Maps SDK for Flutter) verwendet, um zu zeigen, wie diese Funktion implementiert wird.
Der Beispielcode ist auf GitHub veröffentlicht. Wer sofort nachsehen möchte, kann ihn herunterladen. Die Anleitung zur Ausführung der App finden Sie im README . Um das Beispiel auszuführen, benötigen Sie einen API-Schlüssel (kostenlos) . Die Einführung des Karten- SDKs und die Methode zur Kartendarstellung finden Sie im Blogartikel „Erstellen wir eine Karten-App mit Flutter!“. In diesem Artikel liegt der Fokus auf der Funktion zur Anzeige von Offline-Karten.
Offline-Karte (Vektor-Kachel-Layer) erstellen
Diesmal erstellen wir eine Funktion, mit der ein beliebiger Bereich der angezeigten Karte im Gerät heruntergeladen werden kann. Zuerst erstellen wir einen Vektor-Kachel-Layer, der den Download unterstützt und somit offline nutzbar ist.
1. Melden Sie sich bei ArcGIS Online ArcGIS Online oder einem ArcGIS Location Platform Konto an. Falls Sie noch kein Konto haben, können Sie es kostenlos über die Anleitung hier erstellen.
2. Öffnen Sie den Link hier, um die Liste der ArcGIS Basemap Styles Dienste (Vektor-Kachel-Layer) anzuzeigen.
3. Wählen Sie aus den Elementen mit dem Namen „(for Developers)“ einen beliebigen Eintrag wie „World Street Map (Straßenkarte)“ oder „World Topographic Map (Topographische Karte)“ aus. Klicken Sie auf den Namen des ausgewählten Elements und dann unten links auf [Details anzeigen].
4. Klicken Sie oben rechts auf [Mit Vector Tile Style Editor bearbeiten].Vector Tile Style Editor, mit dem Sie das Aussehen der Karte je nach Verwendungszweck individuell anpassen können. Weitere Details zum Editor finden Sie auch im Artikel hierの記事もご覧ください。
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,
);
// Parameter und Downloadziel festlegen und den Task-Job (ExportVectorTilesJob) erstellen.
_exportVectorTilesJob =
vectorTilesExportTask.exportVectorTilesWithItemResourceCache(
parameters: exportVectorTilesParameters,
vectorTileCacheUri: vtpkFile.uri,
itemResourceCacheUri: Uri.directory(resourceDirectoryPath),
);
11. Führen Sie die ExportVectorTilesTask aus, um den Downloadvorgang zu starten. Um den Task auszuführen, rufen Sie die run-Methode des aus dem Task erstellten Jobs (ExportVectorTilesJob) auf. (ExportVectorTilesJob) der run-Methode auf. Wenn der Job erfolgreich ist, erstellen Sie eine neue Offline-Karte aus den heruntergeladenen Vektor-Kacheln.
try {
// Starten Sie den Job und erhalten Sie das Ergebnis.
final result = await _exportVectorTilesJob?.run();
// Wenn der Job erfolgreich ist, erhalten Sie den heruntergeladenen Vektor-Kachel-Cache und den Item-Ressourcen-Cache.
final vectorTilesCache = result?.vectorTileCache;
final itemResourceCache = result?.itemResourceCache;
if (vectorTilesCache == null || itemResourceCache == null) {
showErrorDialog('Vektor-Kachel-Cache oder Item-Ressourcen-Cache ist ungültig');
return;
}
// Erstellen Sie eine Vektor-Kachelebene aus den heruntergeladenen Vektor-Kacheln.
final localVectorTileLayer = ArcGISVectorTiledLayer.withVectorTileCache(
vectorTilesCache,
itemResourceCache: itemResourceCache,
);
// Erstellen Sie eine Offline-Karte mit der Basiskarte, die die Vektor-Kachelebene enthält.
_mapViewController.arcGISMap = ArcGISMap.withBasemap(
Basemap.withBaseLayer(
localVectorTileLayer,
),
);
} on ArcGISException catch (e) {
showErrorDialog(e.message);
} finally {
_exportVectorTilesJob = null;
}
12. Blenden Sie abschließend den Indikator aus.
// Blenden Sie den Indikator aus.
setState(() {
_loading = false;
});
13. Erstellen Sie anschließend die Funktion showErrorDialog , um Fehlermeldungen anzuzeigen.
void showErrorDialog(String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Info', style: Theme.of(context).textTheme.titleMedium),
content: Text(
'Der Download der Vektor-Kacheln ist fehlgeschlagen:\n$message',
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Schließen'),
),
],
),
);
}
14. Erstellen Sie die Funktion takeOnline , die ausgeführt wird, wenn die Schaltfläche „Online anzeigen“ gedrückt wird. Um die aktuell angezeigte Karte von einer Offline- zu einer Online-Karte zu wechseln, setzen Sie die Variable ' _mapViewController.arcGISMap ' . auf ' _onlineMap ' .
_mapViewController.arcGISMap = _onlineMap;
}
15. 今の状態では、_onlineMap が空のため、マップの初期作成時に _onlineMap に現在のマップを保存します。_onMapViewReady 関数の最後に下記を追加します。
void _onMapViewReady() {
・・・省略・・・
_mapViewController.arcGISMap = map;
// 追加
// オンラインマップへの切替用に、現在のマップ状態を保存します。
_onlineMap = map;
}
16. 以上でダウンロード機能の実装は完了です。ビルドして任意の場所をダウンロードしてみてください (現在のマップの表示範囲のデータがダウンロードされます) 。ダウンロードが完了すると、その範囲のデータしか表示されていないことが分かります。
まとめ
本記事では、オフラインマップの表示機能を実装しました。ExportVectorTilesTask や ExportVectorTilesJob では、マップを任意のスケールでダウンロードしたり、ダウンロード処理を途中で停止/再開したり、処理の進捗状況を確認したりといった設定も可能です。 また、今回実装したようにベースマップをインターネットを介してダウンロードする方法以外にも、事前にパッケージ ファイルを作成しておき、そのローカル データをアプリで表示することも可能です。利用可能なオフライン機能については、こちらのページもご覧ください。
関連リンク