XamarinでGoogleMap上の現在地にピンを打ってみる

注意書き

本記事で紹介するパッケージ『Xam.Plugin.Geolocator』は現在『Xamarin.Essentials』に事実上統合されました。『Xam.Plugin.Geolocator』での現在地の取得が出来ない場合は『Xamarin.Essentials』をご利用ください。

私は本記事執筆時には動作を確認することが出来ましたが、2019年6月4日頃に再度実行したところ、理想通りの動きとなりませんでした。


出張や業務が立て込んでいたこともあり、しばらくXamarinから遠ざかってしまいました。

開発環境にそれなりのスペックが求められるため、8年前のノートPCでは起動すら断念しました…。

さて、今回は前回のTODOコメントを解消していきましょう。前回がかなり昔なのでリンク張っておきます。

前回の時点では現在地を取得できず、ハードコーディングになっていました。

ハードコーディングしていた部分を動的取得に変更し、さらにはピンを打ってみたいと思います。

※『ピン』というのはGoogleMapのアイコンにも描かれている、特定の地点をタップした時に出てくる赤いマーカーです。

環境
  • VisualStudio2019
  • .NET Standard 2.0
  • Android 7.1

『Xam.Plugin.Geolocator』のインストール

現在地の取得を行うために、今回は『Xam.Plugin.Geolocator』というNugetパッケージを使用していきます。

ソリューションを右クリックし、『ソリューションのNugetパッケージの管理』を選択します。(プロジェクト右クリックでもOKです)

Xam.Plugin.Geolocator』を共通プロジェクトにインストールします。

GPSアクセス要求の設定

現在地取得を行うにあたり、アプリからAndroidのGPS機能にアクセスを行う必要があります。

よくアプリインストール時に「〇〇へのアクセスを許可しますか?」というポップアップが出てきますよね、アレです。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Androidプロジェクトの『AndroidManifest.xml』に、『ACCESS_COARSE_LOCATION』を追加します。

※以前はAndroidプロジェクトを右クリック⇒『プロパティ』で開く『Androidマニフェスト』の中でドロップダウンリスト形式からの選択が出来た記憶があるのですが、いつのまにやら変わっていたようです。

保存するのを忘れないようにしてください。

実装

Viewは前回と変わらず同じものを使用します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
             xmlns:bindings="clr-namespace:Xamarin.Forms.GoogleMaps.Bindings;assembly=Xamarin.Forms.GoogleMaps.Bindings"
             x:Class="GoogleMapsSample.Views.MainPage"
             Title="{Binding Title}">

    <maps:Map>
        <maps:Map.Behaviors>
            <bindings:MoveToRegionBehavior Request="{Binding MoveToRegionRequest}"/>
        </maps:Map.Behaviors>
    </maps:Map>

</ContentPage>

ViewModelにて現在位置の動的取得を行い、表示範囲の変更を行います。

現在位置の取得に関してはViewModelに実装するか、Modelに実装するか悩ましい所でしたが、仕事じゃないのでViewModelにて実装しました。

using Plugin.Geolocator;
using Plugin.Geolocator.Abstractions;
using Prism.Commands;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms.GoogleMaps;
using Xamarin.Forms.GoogleMaps.Bindings;

namespace GoogleMapsSample.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        // 表示位置移動用
        public MoveToRegionRequest MoveToRegionRequest { get; } = new MoveToRegionRequest();

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="navigationService"></param>
        public MainPageViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            Title = "Main Page";

            DispRouteCommand = new DelegateCommand(async () => await DispRoute());
        }

        /// <summary>
        /// 画面遷移時処理
        /// </summary>
        /// <param name="parameters"></param>
        public override async void OnNavigatedTo(NavigationParameters parameters)
        {
            base.OnNavigatedTo(parameters);

            // 画面遷移後に現在位置へ移動する
            await MoveToCurrentLocation();
        }

        /// <summary>
        /// 現在位置へ移動するメソッド
        /// </summary>
        public async Task MoveToCurrentLocation()
        {
            // 現在地点の座標取得
            IGeolocator locater = CrossGeolocator.Current;
            Plugin.Geolocator.Abstractions.Position geoCurrentPosition = await locater.GetPositionAsync();

            // PositionのConvert
            Xamarin.Forms.GoogleMaps.Position xamCurrentPosition =
                new Xamarin.Forms.GoogleMaps.Position(geoCurrentPosition.Latitude, geoCurrentPosition.Longitude);

            // 表示範囲を現在位置へ移動
            MoveToRegionRequest.MoveToRegion(new MapSpan(xamCurrentPosition, 0.3d, 0.3d));
        }
    }
}

実行結果がこちらです。

最後の方でネタ明かししますが、エミュレーター開発環境においては上記のように表示されればOKです。

ピンの表示

現在位置まで表示出来たところで、次は現在位置にピンを打ってみましょう。

Viewにピンのバインドを行う『BindingPinsBehavior』を追加します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
             xmlns:bindings="clr-namespace:Xamarin.Forms.GoogleMaps.Bindings;assembly=Xamarin.Forms.GoogleMaps.Bindings"
             x:Class="GoogleMapsSample.Views.MainPage"
             Title="{Binding Title}">

    <maps:Map>
        <maps:Map.Behaviors>
            <bindings:MoveToRegionBehavior Request="{Binding MoveToRegionRequest}"/>
            <bindings:BindingPinsBehavior Value="{Binding Pins}"/>
        </maps:Map.Behaviors>
    </maps:Map>

</ContentPage>

ViewModelではPinオブジェクトに現在位置情報を設定し、バインドオブジェクトに追加するだけでOKです。

using Plugin.Geolocator;
using Plugin.Geolocator.Abstractions;
using Prism.Commands;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms.GoogleMaps;
using Xamarin.Forms.GoogleMaps.Bindings;

namespace GoogleMapsSample.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        // 表示位置移動用
        public MoveToRegionRequest MoveToRegionRequest { get; } = new MoveToRegionRequest();

        // ピン
        private Pin _pin;
        public Pin Pin
        {
            get => _pin;
            set => SetProperty(ref _pin, value);
        }
        public ObservableCollection<Pin> Pins { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="navigationService"></param>
        public MainPageViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            Title = "Main Page";

            DispRouteCommand = new DelegateCommand(async () => await DispRoute());
        }

        /// <summary>
        /// 画面遷移時処理
        /// </summary>
        /// <param name="parameters"></param>
        public override async void OnNavigatedTo(NavigationParameters parameters)
        {
            base.OnNavigatedTo(parameters);

            // 画面遷移後に現在位置へ移動する
            await MoveToCurrentLocation();
        }

        /// <summary>
        /// 現在位置へ移動するメソッド
        /// </summary>
        public async Task MoveToCurrentLocation()
        {
            // 現在地点の座標取得
            IGeolocator locater = CrossGeolocator.Current;
            Plugin.Geolocator.Abstractions.Position geoCurrentPosition = await locater.GetPositionAsync();

            // PositionのConvert
            Xamarin.Forms.GoogleMaps.Position xamCurrentPosition =
                new Xamarin.Forms.GoogleMaps.Position(geoCurrentPosition.Latitude, geoCurrentPosition.Longitude);

            // 表示範囲を現在位置へ移動
            MoveToRegionRequest.MoveToRegion(new MapSpan(xamCurrentPosition, 0.3d, 0.3d));

            // 現在地点にピンを打つ
            Pin pin = new Pin();
            pin.Label = "現在地点";
            pin.Position = xamCurrentPosition;
            Pins.Add(pin);
        }
    }
}

実行結果がこちらです。

以前まではラベルも表示されていたのですが、ちょっと仕様が変わったみたいですね。

ネタ明かし

現在位置を指す箇所を拡大してみると…。

本拠地が表示されます。「なるほど…!」って納得しました。

まとめ

  • 現在位置の取得には『Xam.Plugin.Geolocator』を使う。
  • GoogleMap上にピンを表示するには『BindingPinsBehavior』を使う。

次はルートの表示かGoogleが提供する各種APIを使用した開発などを紹介していく予定です。

以上です。

コメント

タイトルとURLをコピーしました