Xamarin.FormsでMapを使うチュートリアルメモ
Xamarin.Forms Essentialでは外部のMapアプリ(Google Mapなど)を呼び出している.
この動画で使用しているのはアプリケーション内でMapの機能を利用する方法.
こんな感じでアプリ内で地図を表示させることができる.
ピンも立てられるようだ.
Xamarin.Forms.Mapのインストール
すべてのプロジェクトに追加する.
iOS
AppDelegate.cs
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { Xamarin.FormsMaps.Init();//これ global::Xamarin.Forms.Forms.Init(); LoadApplication(new App()); return base.FinishedLaunching(app, options); }
Android
MainActivity.cs
protected override void OnCreate(Bundle savedInstanceState) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; base.OnCreate(savedInstanceState); Xamarin.FormsMaps.Init(this, savedInstanceState);//これ Xamarin.Essentials.Platform.Init(this, savedInstanceState); global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); }
マニフェストの編集
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.mapapp"> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <application android:label="MapApp.Android"> <!--これ--> <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" /> </manifest>
Info.plist
<dict> ... <key>NSLocationAlwaysUsageDescription</key> <string>Can we use your location at all times?</string> <key>NSLocationWhenInUseUsageDescription</key> <strin>Can we use your location when your app is being used?</strin> <key>NSLocationAlwaysAndWhenInUseUsageDesription</key> <string>Can we use your location at all times?</string> </dict>
Google Map APIキーを取得する
Google Map APIキーの取得についてはこちらの記事を参考にしてください.
JSONからクラスを生成する
サンプルデータのPlaces.jsonファイルを追加する.
Places.jsonファイルのBuild ActionをEmbedded resourceにする.
Places.json内のデータをコピーしてクリップボードに入れた状態で,Visual StudioのメニューからEdit -> Paste Special -> Paste JSON as Classesを選ぶと,JSONからクラスを生成してくれる.
ルートオブジェクトの名前がRootobject
になっているので,それをPlaces
に変更しておく.
public class Places { public object[] html_attributions { get; set; } public string next_page_token { get; set; } public Result[] results { get; set; } public string status { get; set; } }
あとPlace
クラスを追加する.
public class Place { public string PlaceName { get; set; } public string Address { get; set; } public string Icon { get; set; } public string Distance { get; set; } public string OpenNow { get; set; } public Position Position { get; set; } public Location Location { get; set; } }
Places.jsonのデータを読み込んでMapコントロールに表示する
public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); //Mapの描画が終わるのを待っている? Task.Delay(2000); UpdateMap(); } List<Place> placesList = new List<Place>(); private void UpdateMap() { try { //Embedded resourceのPlaces.jsonを読み込む.文字列として var assembly = IntrospectionExtensions.GetTypeInfo(typeof(MainPage)).Assembly; Stream stream = assembly.GetManifestResourceStream("MapApp.Places.json"); string text = string.Empty; using (var reader = new StreamReader(stream)) { text = reader.ReadToEnd(); } //文字列のJsonをPlacesオブジェクトに変換する var resultObject = JsonConvert.DeserializeObject<Places>(text); //場所の情報PlaceをListに追加する. foreach (var place in resultObject.results) { placesList.Add(new Place { PlaceName = place.name, Address = place.vicinity, Location = place.geometry.location, Position = new Position(place.geometry.location.lat, place.geometry.location.lng), //Icon = place.icon, //Distance = $"{GetDistance(lat1, lon1, place.geometry.location.lat, place.geometry.location.lng, DistanceUnit.Kiliometers).ToString("N2")}km", //OpenNow = GetOpenHours(place?.opening_hours?.open_now) }); } MyMap.ItemsSource = placesList; //PlacesListView.ItemsSource = placesList; //var loc = await Xamarin.Essentials.Geolocation.GetLocationAsync(); MyMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(47.6370891183, -122.123736172), Distance.FromKilometers(100))); } catch (Exception ex) { Debug.WriteLine(ex); } } }
いざ実行
APIキーもセットして実行してみると,以下のようなエラーが出ました. 「Java.Lang.NoClassDefFoundError: 'Failed resolution of: Lorg/apache/http/ProtocolVersion;'」
これは以下の情報によると,この項目をAndroidManifest.xml内の
<uses-library android:name="org.apache.http.legacy" android:required="false" />
これでAndroidManifest.xmlは以下のようになります. 「INETERNET」の許可も追加しました.
<?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>
表示されました.