shuhelohelo’s blog

C#、WPF、Xamarin.Formsが好きですが、ASP.NET Coreも好きです。

Xamarin.Forms.GoogleMapsを使ってみる

github.com

モバイルアプリに地図はとてもよくある組み合わせです.

アプリに地図の機能を追加するときにXamarin.Forms.Mapsライブラリがありますが,これは必要最低限の機能しかなく,かゆいところに手が届かない感じがあります.

そこでXamarin.Forms.GoogleMapsを使うと多機能な地図をアプリに組み込む事ができ,素晴らしく便利です.

Xamarin.Forms.Mapsとの機能比較

|機能|X.F.Maps|X.F.GoogleMaps| こんなに... | ------------------- | :-----------: | :-----------: | |地図の種類|Yes|Yes| |渋滞状況地図|-|Yes| |地図イベント|-|Yes| |地図の移動(アニメーション付き)|Yes|Yes| |地図の移動(アニメーション無し)|-|Yes| |ピン|Yes|Yes| |カスタムピン|-|Yes| |ピンのドラッグ&ドロップ|-|Yes| |ポリゴン|-|Yes| |ライン|-|Yes| |円|-|Yes| |カスタム地図タイル|-|Yes|

Xamarin.Forms.GoogleMapsをインストール

Nugetからインストールする.

f:id:shuhelohelo:20200101161328p:plain

Android

MainActivity.csのOnCreateメソッド内にXamarin.FormsGoogleMaps.Init(this,savedInstanceState)を追加する.

        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            Xamarin.FormsGoogleMaps.Init(this,savedInstanceState);//これ.GoogleMaps

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }

APIキーの設定

Google Map APIAPIキーはGoogle API Consoleで作成しておきます.

shuhelohelo.hatenablog.com

AndroidManifest.xml内に,<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" /><uses-library android:name="org.apache.http.legacy" android:required="false" />を追加する.

この「YOUR_API_KEY」の部分に取得したGoogle MapのAPIキーを貼り付けます.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.mapapp" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="29" />
    <application android:label="MapApp.Android">
    <!--これ重要-->
        <uses-library android:name="org.apache.http.legacy" android:required="false" />
        <!--これ-->
        <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

インターネットへの接続が必要なのでAndroidプロジェクトのプロパティから「INTERNET」のパーミッションを与えておく.

f:id:shuhelohelo:20200102005604p:plain

View側で使う

使い方はXamarin.Forms.Mapsと基本的には同じ.

この例ではMainPageにMapコントロールを配置するものとする.

Xamarin.Forms.GoogleMaps名前空間を追加する.

ContentPageに以下の1行を追加する.

xmlns:map="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"

Mapコントロールを配置する

        <map:Map
            x:Name="MyMap"
            HasZoomEnabled="True"
            MapType="Street" />

ここまででMainPage.xamlは以下のようになっている.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="XFGoogleMapsPractice.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:map="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <map:Map
            x:Name="MyMap"
            HasZoomEnabled="True"
            MapType="Street" />
    </Grid>
</ContentPage>

コードビハインドを少し

MainPage.xaml.csを以下のように変更し,東京を中心に表示させるようにする.これは任意.

        protected override void OnAppearing()
        {
            base.OnAppearing();

            try
            {
                //東京へ移動させる
                MyMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(35.6762, 139.6503), Distance.FromKilometers(100)));
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

実行する

ここまでで実行すると,以下のように東京を中心としてマップが表示される.

f:id:shuhelohelo:20200102023217p:plain

ピンを立てる

ピンを立てるにはPinオブジェクトをMapコントロールPinsプロパティにAddするだけでよい.

追加するだけでマップにピンが表示される.

        protected override void OnAppearing()
        {
            base.OnAppearing();

            try
            {
                //東京へ移動させる
                MyMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(35.6762, 139.6503), Distance.FromKilometers(100)));

                //ピンを立てる
                var pin = new Pin()
                {
                    Type = PinType.Place,
                    Label = "New Place",
                    Address = "Hello Tokyo",
                    Position = new Position(35.6762, 139.6503),//東京
                    Rotation = -33.3f,//ピンを傾けることができる
                    Tag = "",
                };
                MyMap.Pins.Add(pin);//マップへ追加
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

ピンをタップすると,LabelとAddressプロパティで設定した文字列が表示される.

f:id:shuhelohelo:20200102023726p:plain

変更通知などを書く必要がなく,Pinsプロパティに追加するだけマップ上にピンが立つのでとても使いやすくなっている.

ピンのドラッグアンドドロップ

ピンをドラッグアンドドロップして移動させる,というのは個人的にとても必要な機能で,なんというかもう素晴らしいの一言に尽きます.

この機能はPinオブジェクトのIsDraggableプロパティをtrueにするだけで使えます.

                var pin = new Pin()
                {
                    Type = PinType.Place,
                    Label = "New Place",
                    Address = "Hello Tokyo",
                    Position = new Position(35.6762, 139.6503),//東京
                    Rotation = -33.3f,//ピンを傾けることができる
                    Tag = "",
                    IsDraggable=true,//これだけでピンを長押しすると移動モードになる
                };

たった1行足すだけです.

f:id:shuhelohelo:20200102025433g:plain

長押しイベント

Clickイベント(MapClicked)だけでなく長押し(MapLongClicked)イベントがあるので,操作の幅が広がります.

例えば,ピンを追加するときに使えます.タップイベントだと意図せずピンを立ててしまうことになりがちですが,長押しにすることで明確な意図をもってピンを立てるという操作にすることができます.

MapコントロールのMapLongClickedイベントにイベントハンドラを設定します.

        <map:Map
            x:Name="MyMap"
            HasZoomEnabled="True"
            MapType="Street" 
            MapLongClicked="MyMap_MapLongClicked"/>
        private void MyMap_MapLongClicked(object sender, MapLongClickedEventArgs e)
        {
            var pin = new Pin()
            {
                Type = PinType.Place,
                Label = "Long Tapped",
                Address = "Added New Pin",
                Position = e.Point,//長押しした地図上の位置
                Rotation = 33.3f,
                Tag = "",
                IsDraggable = true,
            };
            MyMap.Pins.Add(pin);
        }

シンプルでわかりやすい!

まとめ

ほんの一部ですが,Xamarin.Forms.GoogleMapsの機能を紹介しました.

多機能な上に使いやすく,地図を使ったアプリを作る際に重宝すると思います.

作者のamay077さんのリポジトリにはサンプルアプリもついているので,そちらを動かしてみるとより理解が深まると思います.

今回のソースコード

github.com