Flutter This is a blog series introducing features useful for map app development with Flutter. This article covers address search. It implements two features: moving the map to the location of the entered address and displaying the address of the tapped location on the map. 2 features will be implemented. In this article,Flutter map SDK (ArcGIS Maps SDK for Flutter) is used to demonstrate how to implement these features.
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 the README に記載しています。サンプルを実行するために、API キーの取得 (無償) が必要になります。
地図 SDK の導入からマップ表示までの方法は「Flutter で地図アプリを作成してみよう!」のブログ記事をご覧ください。この記事では、住所検索の機能にフォーカスして紹介します。
住所検索
住所検索機能を使用するには、LocatorTask クラスを使用します。LocatorTask には、大きく分けて、以下の 2 つの機能が提供されています。
ジオコーディング機能の実装
まずは、住所文字列から該当する場所を検索するジオコーディング機能を実装していきます。
1. 「Flutter で地図アプリを作成してみよう!」のブログ記事の手順 6 で、マップビュー コントローラーに作成したマップを設定してマップの表示までできたら、_MyHomePageState クラスの最初で、LocatorTask.withUri コンストラクターを使用して LocatorTask を作成します。
class _MyHomePageState extends State<MyHomePage> {
// 追加
//ジオコードサービスの URL を指定して、ジオコーディング用のタスクを作成します。
final _locatorTask = LocatorTask.withUri(
Uri.parse(
'https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer',
),
);
・・・
ジオコードサービスには、ArcGIS Location Platform のサービスを使用します。住所検索(ジオコーディング/リバースジオコーディング)は、毎月 20,000 回まで無償で利用できます。
2. 続いて、ジオコーディングに使用する住所を入力するためのテキスト入力フォームを作成します。テキスト入力フォームには、Flutter の TextField ウィジェットを使用します。_MyHomePageState クラスの最初で、TextField ウィジェットに設定する _textEditingController と _searchFocusNode 変数を作成します。TextEditingController は、初期状態で表示されるテキストの設定と現在のテキストの取得に使用し、FocusNode はウィジェットのフォーカス状態を管理するのに使用します。
class _MyHomePageState extends State<MyHomePage> {
// 追加
final _textEditingController = TextEditingController(text: '東京都千代田区平河町2-7-1');
final _searchFocusNode = FocusNode();
・・・
3. 続いて Widget build() の Column ウィジェット内にある ArcGISMapView ウィジェットの前に TextField ウィジェットを追加します。
mainAxisAlignment: MainAxisAlignment.center,
children: [
//追加
TextField(
focusNode: _searchFocusNode,
controller: _textEditingController,
decoration: InputDecoration(
hintText: '住所を入力...',
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
onPressed: dismissSearch,
icon: const Icon(Icons.clear),
),
),
onSubmitted: onSearchSubmitted,
),
Expanded(
// ウィジェット ツリーにマップビューを追加し、コントローラーを設定します。
child: ArcGISMapView(
・・・
4. TextField のフォームで住所の入力が完了した時に実行される onSearchSubmitted メソッド(TextField の onSubmitted プロパティに設定)を作成します。onSearchSubmitted メソッドでは、LocatorTask を使用してジオコーディングを行い、その結果の座標にマーカーを表示する処理を実装しています。
void onSearchSubmitted(String value) async {
// ジオコーディング(文字列から座標を取得)用の検索パラメーターを作成します。
final geocodeParameters = GeocodeParameters()
..outputSpatialReference = _mapViewController.spatialReference;
// TextField に入力された文字列をもとにジオコーディングを実行して結果を取得します。
final geocodeResult = await _locatorTask.geocode(
searchText: value, parameters: geocodeParameters);
if (geocodeResult.isEmpty) return;
final firstResult = geocodeResult.first;
// 結果の座標にアイコンを表示して、中心になるようにマップを移動します。
final pictureMarkerSymbol = PictureMarkerSymbol.withUri(Uri.parse(
"https://static.arcgis.com/images/Symbols/Shapes/BlueStarLargeB.png"));
pictureMarkerSymbol.height = 50;
pictureMarkerSymbol.width = 50;
final graphic = Graphic(
geometry: firstResult.displayLocation, symbol: pictureMarkerSymbol);
_mapViewController.graphicsOverlays[0].graphics.add(graphic);
_mapViewController.setViewpointCenter(firstResult.displayLocation!);
}
5. 続いて、テキスト入力フォームの右横にある [X] アイコンをタップしたときに実行される dismissSearch メソッド(IconButton の onPressed プロパティに設定)を作成します。dismissSearch メソッドでは、テキスト入力フォームのテキストをクリアして、キーボードを閉じる処理を実装しています。
void dismissSearch() {
// テキスト フィールドをクリアして、キーボードを閉じます。
setState(() => _textEditingController.clear());
FocusManager.instance.primaryFocus?.unfocus();
}
6. これでジオコーディング機能を実装できたので、この状態でビルドして、機能を試してみます。住所を入力し、キーボードの完了ボタン等をタップして住所の入力を完了すると、マップ上の該当する場所にアイコンが表示されます。
リバースジオコーディング機能の実装
7. 続いて、リバースジオコーディングの機能を実装していきます。既に作成済みの ArcGISMapView ウィジェットに、マップをタップした時に呼び出される onTap プロパティを設定します。
child: ArcGISMapView(
controllerProvider: () => _mapViewController,
onMapViewReady: _onMapViewReady,
//追加
onTap: onSearchTap,
),
8. マップ上をタップした時に実行される onSearchTap メソッドを設定します。onSearchTap メソッドでは、LocatorTask を使用してリバースジオコーディングを行い、その結果の住所テキストを表示する処理を実装しています。
void onSearchTap(Offset localPosition) async {
// 既存のグラフィックスを削除します。
final graphicsOverlay = _mapViewController.graphicsOverlays[0];
if (graphicsOverlay.graphics.isNotEmpty) graphicsOverlay.graphics.clear();
// スクリーン ポイントをマップ ポイントに変換します。
final mapTapPoint =
_mapViewController.screenToLocation(screen: localPosition);
if (mapTapPoint == null) return;
// タップした場所を示すグラフィックス オブジェクトを作成します。
final pictureMarkerSymbol = PictureMarkerSymbol.withUri(Uri.parse(
"https://static.arcgis.com/images/Symbols/Shapes/BlueStarLargeB.png"));
pictureMarkerSymbol.height = 50;
pictureMarkerSymbol.width = 50;
graphicsOverlay.graphics.add(Graphic(geometry: mapTapPoint));
// リバースジオコーディング(座標から住所を取得)用の検索パラメーターを作成します。
final reverseGeocodeParameters = ReverseGeocodeParameters()..maxResults = 1;
// タップした場所とパラメーターを使用してリバースジオコーディングを実行します。
final reverseGeocodeResult = await _locatorTask.reverseGeocode(
location: mapTapPoint,
parameters: reverseGeocodeParameters,
);
if (reverseGeocodeResult.isEmpty) return;
// 結果から住所文字列を取得してダイアログに表示します。
final firstResult = reverseGeocodeResult.first;
final addressString = firstResult.label;
if (mounted) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(content: Text(addressString));
},
);
}
}
9. Now that the reverse geocoding feature has been implemented, I will build and test the functionality. When you tap any location on the map, the address text for that location will be displayed on the map.
Summary
In this article,LocatorTask class was used to implement geocoding and reverse geocoding features. Although not fully covered in this article,LocatorTask class provides several useful parameters that can be used during search. In geocoding, you can specify thegeographic extentto search within, and also set amatch score thresholdbetween the search string and actual address string to allow for fuzzy matching. In reverse geocoding, you can also set thedisplay language of the returned address.The image below shows the same address displayed in Japanese and English, demonstrating that you can implement a feature to switch the address display language based on the user's selection.
Related Links