
.NET MAUIで地図タイルを重ねる実装 — 透明度合成の作り方
⚠ 以前の記事「地図を3枚、1画面で — 背景地図の重ね合わせと透明度調整で現場資料を持ち歩かない」では、現場での使い方(Apple Map+背景地図2枚+透明度調整で複数資料を1画面に照合する)を紹介しました。今回はその実装版です。「概念→実装」の視点で、.NET MAUIアプリのどこにその機能が実際に組み込まれているかを見ていきます。
完成形のおさらい

Apple Mapをベースに、背景地図を最大2枚まで重ね、各背景の透明度を個別に調整できる——という機能です。実装の中身は、MAUIの標準地図コントロールだけでは足りず、プラットフォーム固有のカスタムハンドラーを書く形になっています。
MAUI標準の地図コントロールでは足りなかったこと
.NET MAUIの Microsoft.Maui.Controls.Maps.Map は、ピンや簡単な図形描画はサポートしていますが、XYZ形式のタイル画像をURLから取得して背景に重ねる、という用途は標準機能の範囲外です。GDEでは、iOS側で MapHandler を継承した CustomMapHandler を用意し、ネイティブの MKMapView に直接アクセスして、地理院タイルのようなXYZタイルサーバのURLテンプレートから画像を取得・描画する仕組みを組み込んでいます。
タイルオーバーレイの実装:CustomTileOverlay
背景タイルは、iOSのMapKitが提供する MKTileOverlay を継承した CustomTileOverlay というクラスで表現されています。コンストラクタには背景地図の名称・XYZタイルサーバのURLテンプレート・背景地図番号(0か1)を渡します。GDEでは背景を2枚までという制限に合わせて、TileOverlay0 と TileOverlay1 という2つのスロットを持たせる設計にしています。
public class CustomTileOverlay : MKTileOverlay
{
public CustomTileOverlay(string name, string urlTemplate, int overLayNo)
: base(urlTemplate)
{
this.CanReplaceMapContent = false;
// ...
}
}
CanReplaceMapContent を false にしているのは、タイルオーバーレイがベースのApple Map自体を置き換えるのではなく、あくまで上に重ねる表示にするためです。
透明度合成:MKTileOverlayRendererのAlphaプロパティ
透明度調整は、MKTileOverlayRenderer の Alpha プロパティで実現しています。オーバーレイごとの透明度は設定値(TileAlpha0 / TileAlpha1)として保持し、レンダラーを生成するタイミングでそのまま適用します。
MKTileOverlayRenderer tileRenderer = new MKTileOverlayRenderer((CustomTileOverlay)overlay);
if (overlay == TileOverlay0)
{
if (App.gConfig.INFO.TileAlpha0 < 0.1f)
{
App.gConfig.INFO.TileAlpha0 = 0.1f;
}
tileRenderer.Alpha = App.gConfig.INFO.TileAlpha0;
}
ポイントは、透明度の下限を 0.1f にクランプしていることです。ユーザーが誤ってスライダーを0まで下げてしまうと、背景タイルが完全に見えなくなり「表示されているのに何も見えない」状態になって操作が分かりにくくなります。下限を設けることで、常に薄くでも重なっている層の存在が視認できるようにしています。
オーバーレイを地図に挿入する際は MKOverlayLevel.AboveRoads を指定しています。これは「道路レイヤーより上・測点ピンやポリラインなどの図形要素より下」という重ね順で、タイル画像が測点表示を隠してしまわないようにするための配置です。
MAUI特有の落とし穴:オーバーレイが消える
実装で一番手間取ったのは、透明度合成そのものより「MAUIがネイティブの地図ビューを再構築するタイミングで、独自に追加したタイルオーバーレイが消えてしまう」という挙動でした。MAUIの MapElements(ピンやポリラインなどのコレクション)が変更されると、MAUI側がネイティブの MKMapView のオーバーレイ構成を作り直すことがあり、その際にコード側から InsertOverlay で追加したカスタムタイルオーバーレイが一緒に消えてしまうことがあります。
対策として、MapElements の変更イベントを監視し、変更のたびに「カスタムタイルオーバーレイがまだ地図に存在するか」を確認、消えていれば再度 InsertOverlay で挿入し直す、という復元処理を入れています。オーバーレイの重ね順管理と、この復元処理をセットで持たせないと、測点を追加・更新するたびに背景タイルがふっと消えるという不具合になります。
積み残し:タイルキャッシュは現状無効
XYZTileCache / XYZDatabase という、取得したタイル画像をローカルDBにキャッシュするためのクラス自体は用意されているものの、現状は .NET 8 MAUI の制約により LoadTileAtPath が呼ばれず、キャッシュは無効な状態です(コード内のログにもその旨が明記されています)。電波の弱い現場でタイルを何度も再取得する非効率は残っており、この部分は今後の改善余地として残されています。
まとめ
- MAUI標準の地図コントロールにはXYZタイル背景の重畳機能がないため、iOS側で
MapHandlerを継承したカスタムハンドラーを実装している。 - タイルは
MKTileOverlay継承クラスで表現し、透明度はMKTileOverlayRenderer.Alphaで背景ごとに個別制御。下限0.1のクランプで「消えて見えなくなる」事故を防いでいる。 - MAUIがネイティブ地図ビューを再構築する際にカスタムオーバーレイが消える問題があり、変更イベント監視による自動復元で対処している。
- タイルキャッシュの仕組みは用意済みだが、.NET 8 MAUIの制約で現状は無効という積み残しがある。
関連記事
- 地図を3枚、1画面で — 背景地図の重ね合わせと透明度調整で現場資料を持ち歩かない(概念・現場活用編)
- .NET MAUI アプリ3本を .NET 8 から .NET 10 へ移行した
- 地理院タイルのしくみ — ズームレベルとタイル座標を学ぶ(GeoPrism JP)
- 座標変換エンジンをSwiftとC#で二重実装する — 結果一致の保証
開発者より: アプリ・Kindle本・オープンソースの一覧は GitHub: amru195704 にまとめています。
お願い
本記事の情報は参考目的で掲載しており、正確性・完全性を保証するものではありません。誤記・不正確な情報がございましたら、コメント欄よりご指摘いただければ、確認のうえ修正いたします。

コメントを残す