.NET MAUIで地図表示

地図の操作自体は公式でしっかり解説されてて、移行することはいっぱいあるけど、そんなに大変じゃない感じ。

Pinの外観を変えたい

これは公式に書いてないが、下記のやり方でいけました!ありがたや!
https://vladislavantonyuk.github.io/articles/Customize-map-pins-in-.NET-MAUI/

あと、CreateMauiAppの修正でちょっとはまった。
UseMauiMaps→ConfigureMauiHandlersの順が大事っぽい。

        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                // Mapを利用する
                .UseMauiMaps()
                // カスタム用レンダラーを利用する
                .UseMauiCompatibility()
#if ANDROID
                // Android用クラスインスタンスで生成
                .UseMauiApp<Droid.HogeAppDroid>()
                // Activityインスタンスを渡す
                .ConfigureLifecycleEvents(events =>
                {
                    events.AddAndroid(android => android
                        .OnCreate((activity, bundle) => Droid.HogeAppDroid.OnCreate(activity, bundle))
                        );
                })
                // Android用カスタムコントロールのレンダラーを登録
                .ConfigureMauiHandlers((handlers) =>
                {
                    handlers.AddHandler(typeof(Microsoft.Maui.Controls.Maps.Map), typeof(Droid.CustomMapHandler));
                })
#elif IOS
                // iOS用クラスインスタンスで生成
                .UseMauiApp<iOS.HogeAppIOS>()
                // iOS用カスタムコントロールのレンダラーを登録
                .ConfigureMauiHandlers((handlers) =>
                {
                    handlers.AddHandler(typeof(Microsoft.Maui.Controls.Maps.Map), typeof(iOS.CustomMapHandler));
                })
#endif
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });
#if DEBUG
    		builder.Logging.AddDebug();
#endif

            return builder.Build();
        }

ただ、後からラベルだけ変えるとかはできないっぽい?
変えたきゃPinのインスタンスごと作り直せばいける。

移動は表示してから?

位置の移動処理を実装しておいても、エラーにはならないけど、map.IsVisible = Falseの状態だとAndroidは効果がなかった。
プロパティの変更イベントハンドラを実装して、map.IsVisibleがTrueに変更されたら、別スレッドで1秒ほど待機→移動って処理にして回避。なんでや。

住所情報

以前は文字列で1発でとれたけど、Placemarkクラスの各プロパティを連結する必要がある。
これがAndroidとiOSでもかなり取れ方が違うっぽい。
Androidは同じ情報が複数プロパティに反映されがち。
分けて実装する必要がありそうだった。

/// <summary>
/// 住所更新(ラベル)
/// </summary>
private async Task UpdateAddress( Location pos)
{
string address = "";


// 住所文字処理
try
{
// 住所文字列の取得
IEnumerable<Placemark> addresses = await Geocoding.Default.GetPlacemarksAsync(pos.Latitude, pos.Longitude);
Placemark placemark = addresses?.FirstOrDefault();
// 結果をとる。
if (placemark != null)
{
// AndroidとiOSで結果が異なるので作り方もわける
// 郵便番号はいらない
if (!string.IsNullOrEmpty(placemark.CountryName))
{
// 国名はつける(日本だけ削除)
address = placemark.CountryName.Replace("日本", "");
}
OID
// 郵便番号はいらない
address += placemark.AdminArea // 都道府県
+ placemark.Locality // 市区町村
+ placemark.SubLocality // サブの局所性
+ placemark.Thoroughfare; // 町名

// 丁目
// 四国の海だとCountryNameとFeatureNameに"日本"が設定されて、他のプロパティは空なので
// AdminAreanoの空チェックも行う
if (!string.IsNullOrEmpty(placemark.AdminArea) && !string.IsNullOrEmpty(placemark.SubThoroughfare))
{
// 数字が連結されるならハイフンを挟む
if (IsIntParseOneChar(address, false) && IsIntParseOneChar(placemark.SubThoroughfare, true))
{
address += "‐";
}
address += placemark.SubThoroughfare;
}

// 号
if (!string.IsNullOrEmpty(placemark.AdminArea) && !string.IsNullOrEmpty(placemark.FeatureName))
{
// 数字が連結されるならハイフンを挟む
if (IsIntParseOneChar(address, false) && IsIntParseOneChar(placemark.FeatureName, true))
{
address += "‐";
}
address += placemark.FeatureName;
}

address += placemark.AdminArea // 都道府県
+ placemark.Locality // 市区町村
+ placemark.Thoroughfare; // 町名&丁目

// 番地以降
// 四国の海だとCountryNameとFeatureNameに"日本"が設定されて、他のプロパティは空なので
// AdminAreanoの空チェックも行う
if (!string.IsNullOrEmpty(placemark.AdminArea) && !string.IsNullOrEmpty(placemark.SubThoroughfare))
{
// 数字が連結されるならハイフンを挟む
if (IsIntParseOneChar(address, false) && IsIntParseOneChar(placemark.SubThoroughfare, true))
{
address += "‐";
}
address += placemark.SubThoroughfare;
}

// FeatureNameはSubLocality、Thoroughfare、SubThoroughfareがnullの場合
if (string.IsNullOrEmpty(placemark.SubLocality) && string.IsNullOrEmpty(placemark.Thoroughfare) &&
string.IsNullOrEmpty(placemark.SubThoroughfare) && !string.IsNullOrEmpty(placemark.FeatureName))
{
// 数字が連結されるならハイフンを挟む
if (IsIntParseOneChar(address, false) && IsIntParseOneChar(placemark.FeatureName, true))
{
address += "‐";
}
address += placemark.FeatureName;
}
}
}
catch (Exception ex)
{
DebugLog.Log(ex.Message);

address = "";
}

// ピンを作り直してラベルに住所反映したり・・・
}

/// <summary>
/// 数字始まりまたは数字終わりかチェック
/// </summary>
/// <param name="str">チェックする文字列</param>
/// <param name="isFirst">先頭をチェックするならtrue、末尾ならfalse</param>
/// <returns>数字であればtrue</returns>
private bool IsIntParseOneChar(string str, bool isFirst)
{
// 空ならfalse
if (string.IsNullOrEmpty(str))
{
return false;
}

// 先頭または末尾1文字をチェック
string check = "";
if (isFirst)
{
check = str.Substring(0, 1);
}
else
{
check = str.Substring(str.Length - 1, 1);
}

// Strings.StrConv(check, VbStrConv.Narrow, 0)は使えないので半角に置き換えは手作業で行う
check = check.Replace("0", "0").Replace("1", "1").Replace("2", "2").Replace("3", "3").Replace("4", "4")
.Replace("5", "5").Replace("6", "6").Replace("7", "7").Replace("8", "8").Replace("9", "9");
// 判定
return int.TryParse(check, out _);
}

他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)