.NET MAUIで「処理中(IsBusy=true)の間は画面全体に透明なマスクをかけ、背面のボタンや入力を一切触れないようにしたい」のに、Android実機ではタップが貫通してしまうことがあります。本記事では、BoxView+InputTransparentで起きる代表的な原因と、バージョン更新での改善状況、更新できない場合でも確実に“操作不能状態”を作る実務的な回避策をまとめます。
症状:BoxViewを全画面に重ねても背面がタップできる
質問でよく見かけるのが、ActivityIndicator+透明BoxViewをAbsoluteLayoutの最前面に置き、IsBusyの間だけ表示するパターンです。UIとしては「いかにも覆っている」ように見えるのに、Androidでは背面のボタンが普通に反応してしまう、という現象が起きます。
<AbsoluteLayout VerticalOptions="Fill" BackgroundColor="#5774ED">
<ActivityIndicator IsRunning="{Binding Path=IsBusy, Source={x:Reference MyPage}}"
ZIndex="2"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1" />
<BoxView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
ZIndex="1"
BackgroundColor="Transparent"
InputTransparent="False"
IsVisible="{Binding Path=IsBusy, Source={x:Reference MyPage}}" />
</AbsoluteLayout>
期待する動作は以下のとおりです。
- IsBusy=true:BoxView(透明)を画面全体に表示し、背面のボタンや入力を一切操作できない状態にする
- IsBusy=false:BoxViewを非表示に戻し、通常操作に戻る
しかしAndroidでは、InputTransparent=”False” でも背面がタップできることがあります。
まず理解しておきたい:InputTransparent と CascadeInputTransparent の基本
切り分けを間違えないために、プロパティの意味を整理します。InputTransparentは「透明にする(見た目)」ではなく、ヒットテスト(タッチ/クリック判定)に参加するかどうかを制御します。Microsoft Learnの説明でも、InputTransparentがtrueのときはその要素が入力を受け取らず、背面の要素へ入力が渡る旨が明記されています。
| プロパティ | 対象 | 既定値 | 意味(要点) | よく使う場面 |
|---|---|---|---|---|
| InputTransparent | すべてのVisualElement | false | trueにすると、その要素は入力判定から外れ、背面へ入力が渡る | ヘッダーがリストに被るときに“タップ貫通”させる、装飾要素を入力対象外にする |
| CascadeInputTransparent | Layout(Grid/StackLayoutなど) | true | 親LayoutがInputTransparent=trueのとき、子にも透明設定を引き継ぐかどうか | 親を透明にしても子は操作させたい、逆に親を透明にしたら子も全部操作不可にしたい |
| IsEnabled | 多くのコントロール/レイアウト | true | falseにすると操作不可(見た目も無効化スタイルになる場合あり) | ビジー時の二重送信防止、ポップアップ表示中の背面無効化 |
今回の目的(ビジー中に背面を触らせない)は、理屈の上では InputTransparent=”False” の“全面オーバーレイ”が最短です。実際、AbsoluteLayoutは公式ドキュメントでも「オーバーレイ用途でページを覆い、背面操作を防ぐ」使い方が典型例として挙げられています。
原因:Android向け .NET MAUI で InputTransparent の既知不具合があった
質問のXAML自体はよくある実装で、構造としても間違いとは言い切れません。それでも貫通する場合、Android向け .NET MAUI の InputTransparent 実装の不具合が原因になっているケースがあります。
実際に、BoxViewを前面に置いてInputTransparentを切り替えてもクリックが通ってしまう問題は、GitHubで Issue #9069「InputTransparent property does not work on Android」として報告されています(デモアプリ付きで、InputTransparentの値に関係なくクリックが処理されるという内容)。このIssueは後にクローズされていますが、当時は再現性があり、MAUI側の問題として追跡されていました。
修正の流れ:InputTransparentとCascadeInputTransparentの組み合わせ修正が入った
InputTransparentは単体で完結せず、LayoutのCascadeInputTransparentや親子関係の評価が絡みます。これに対して、さまざまな組み合わせ(親/子、カスケード有無)を正しく扱うための修正として、Pull Request #14846「Implement all permutations of InputTransparent and CascadeInputTransparent」が取り込まれています。PRは2023年7月7日にmainへマージされ、複数の関連Issue(#7489など)を修正対象に含めています。
さらに、InputTransparentの挙動議論が行われた Issue #7489 には、「fixed-in-8.0.0-preview.7.8842」というラベルが付いており、少なくとも.NET MAUI 8のプレビュー段階で修正を含むビルドが案内されています。
Microsoft Q&A側でも、同様の質問(BoxViewにInputTransparent=falseでも貫通する)に対し、当初は #9069 への誘導(再現確認)→ 後年(2025年3月)に「8.0で修正済み、#14846が入っている」といった案内が投稿されています。
重要:8.0で“直ったはず”でも、BoxViewだけ別ルートで再燃することがある
ここが現場で一番ハマりどころです。InputTransparent全体の整理(#14846)とは別に、BoxView(描画系)に限って、Androidで“前面にあるのに背面を触れてしまう”という報告がその後も上がっています。
たとえばGitHubでは、Issue #26026「[Android] BoxView Allows Touch Actions to Below Element When InputTransparent is False」として、BoxViewがInputTransparent=falseでも背面のタッチを防げない問題が報告されています。報告では.NET MAUI 9.0.0 GAで発生し、Android 11以降で再現する旨が記載されています(2024年11月に起票、2025年時点でもOpen)。
つまり、結論を実務寄りに言い換えると次のようになります。
- InputTransparent全体のロジックは8.0で大きく改善された(修正の取り込み・ラベル付けがある)
- ただし「BoxViewを“透明のブロッカー”として使う」ケースは、バージョンや環境によってまだ踏むことがある
- したがって“更新+回避策”をセットで持っておくのが安全
最初にやるべき:MAUIのバージョンとワークロードを確認する
まず「今のアプリがどの系統で動いているか」を把握します。InputTransparent系は修正が段階的に入っているため、ここがズレていると“調べた情報は正しいのに直らない”状態になります。
確認ポイント
- TargetFramework:net7.0-android / net8.0-android / net9.0-android など
- Microsoft.Maui.Controls のバージョン:プロジェクトテンプレートや依存関係で固定されていないか
- dotnet workload:SDKだけ更新しても、maui-androidワークロードが古いままのことがある
更新する場合の定番手順(例)
- .NET SDKを更新(チーム運用ならglobal.jsonも確認)
- ターミナルで dotnet workload update を実行
- Visual Studioを使う場合は、インストーラ側のMAUI/Android SDK関連も更新
- 一度クリーン(bin/obj削除)してビルドし直す
この段階で直るなら、最もコストが低い解決です。逆に、更新しても再現するなら、次の「確実に止める」回避策へ進むのが早いです。
回避策:背面操作を確実に止める“実務用”の選択肢
ここからは「InputTransparentの挙動が環境に左右されても、UIの誤操作や二重送信を起こさない」ことを優先した方法です。ビジー中の操作ブロックは、見た目よりも事故を防ぐ設計が重要なので、堅牢性の高い順に紹介します。
| 方法 | 止め方 | メリット | 注意点 | おすすめ度 |
|---|---|---|---|---|
| 背面コンテナをIsEnabled=false | 根本的に操作不可にする | 最も確実。BoxView依存なし | 無効化スタイルが出る場合あり(必要なら工夫) | 高 |
| オーバーレイを“入力を受ける要素”にする(Button/ContentView+Gesture) | 前面が必ずタップを取る | 見た目を変えずにブロックしやすい | Gestureの実装・アクセシビリティを考慮 | 高 |
| 背面全体をInputTransparent=true | 背面が入力判定から外れる | XAMLがシンプル | InputTransparent自体の不具合に巻き込まれる可能性 | 中 |
| BoxView(透明/半透明)でブロック | 前面でヒットテスト | 見た目が簡単 | AndroidでBoxViewだけ貫通する報告がある | 中〜低 |
回避策の本命:背面コンテナをまとめて IsEnabled で無効化する
「タップを受け止める」よりも確実なのが、背面の操作対象そのものを無効化する方法です。ポップアップ系の背景操作問題でも、最終的にこの回避策が挙げられることが多いです。
実装のコツは、操作対象を1つの親にまとめることです。
<Grid>
<!-- 操作対象をまとめる -->
<Grid x:Name="MainArea"
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBoolConverter}}">
<!-- ボタンや入力など通常UI -->
</Grid>
<!-- ビジー中の表示(操作ブロックはIsEnabled側で担保) -->
<Grid IsVisible="{Binding IsBusy}"
BackgroundColor="#00000000">
<ActivityIndicator IsRunning="True"
VerticalOptions="Center"
HorizontalOptions="Center" />
</Grid>
</Grid>
ポイントは次の通りです。
- 操作ブロックはMainArea.IsEnabled=falseで担保する(オーバーレイ側に依存しない)
- オーバーレイは「見せるだけ」に寄せる(見た目のスピナー、半透明の暗幕など)
- 二重送信や誤操作の事故を最も防げる
「無効化すると見た目が灰色になるのが嫌」という場合は、ボタンのスタイルを調整する、あるいは操作対象を細かく無効化する等の工夫で吸収できます。まずは事故を止めるのが最優先です。
オーバーレイで受け止めたい場合:BoxView以外を“ブロッカー”にする
「背面を無効化するとUIの見た目が崩れる」「処理中でも一部は触れるようにしたい」など、オーバーレイ側でブロックしたい設計もあります。その場合は、BoxViewではなくタップを受け取る前提の要素を使うと安定します。
透明ボタンを全面に置いて“何もしないクリック”を取る
<Grid>
<!-- 背面UI -->
<Grid>
<!-- ここにボタンや入力 -->
</Grid>
<!-- ブロッキング用の透明ボタン(IsBusyで表示) -->
<Button IsVisible="{Binding IsBusy}"
BackgroundColor="#00000000"
Opacity="1"
Text=""
Command="{Binding DummyCommand}" />
<!-- スピナーはさらに前面 -->
<ActivityIndicator IsVisible="{Binding IsBusy}"
IsRunning="{Binding IsBusy}"
VerticalOptions="Center"
HorizontalOptions="Center" />
この方式は泥臭いですが強いです。
- Buttonは“タップを受け取る”ことが前提のため、前面に置けばブロックしやすい
- Commandは空実装でOK(ログを出すだけでも良い)
- アクセシビリティ的にも「処理中に押せない」状態を作りやすい
ContentView+TapGestureRecognizerで受け止める
ボタンを置きたくない場合は、GestureRecognizerを付けて“入力対象にする”方法もあります。
<ContentView IsVisible="{Binding IsBusy}"
BackgroundColor="#00000001">
<ContentView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding DummyCommand}" />
</ContentView.GestureRecognizers>
</ContentView>
BackgroundColorに完全透明ではなく、限りなく透明に近い色を使うのは、環境によってヒットテストや描画系の差異が出ることがあるためです(ただし、環境によっては効果が出ないこともあります)。Microsoft Q&Aでも近い提案が見られます。
BoxViewを使い続けるなら:落とし穴チェックと改善パターン
「デザイン的にBoxView(あるいはShape)で暗幕を出したい」こともあります。その場合は、次のポイントを順に確認すると切り分けが早いです。
オーバーレイが本当に最前面か
- ZIndexを設定していても、親子の階層やレイアウトの構造によっては意図通りにならないことがあります
- 最小構成として、Gridで背面とオーバーレイを2レイヤーに固定して再現するか確認します
親レイアウト側がInputTransparentになっていないか
「オーバーレイのBoxViewはInputTransparent=falseなのに…」というとき、親LayoutがInputTransparent=trueになっていて、子が入力判定から外れているケースがあります。CascadeInputTransparentは既定trueなので、親の設定が子に効くことがあります(レイアウトの入力透過の説明はドキュメントにもあります)。
BoxView特有の不具合に当たっていないか
前述のとおり、BoxViewに限って「InputTransparent=falseでも背面が触れる」報告が残っています。MAUI 8で直ったはずなのに、BoxViewだけ貫通する場合は、InputTransparent全体の話ではなくBoxView/描画系の問題に寄っている可能性があります。再現するなら、BoxViewをButtonやContentViewに置き換えて改善するかで方向性が決まります。
最小再現での切り分けテンプレート
自分のアプリ固有の要因(Shell、モーダル、カスタムコントロール、Behavior、Effects、ハンドラー等)が混ざると判断が難しくなります。まずは“白いプロジェクト”で次の最小構成を作り、挙動が変わるか確認するのがおすすめです。
最小XAML(Grid二層)
<Grid>
<StackLayout Spacing="16" Padding="24">
<Button Text="背面ボタン"
Clicked="OnClicked" />
<Label x:Name="ResultLabel" Text="未クリック" />
</StackLayout>
<!-- ここを BoxView / ContentView / Button で差し替えて比較 -->
<BoxView IsVisible="{Binding IsBusy}"
BackgroundColor="Transparent"
InputTransparent="False" />
<ActivityIndicator IsVisible="{Binding IsBusy}"
IsRunning="{Binding IsBusy}"
VerticalOptions="Center"
HorizontalOptions="Center" />
見るべきポイント
- IsBusy=trueのとき、背面ボタンが反応するか
- BoxView→ContentView+Gestureに置き換えると止まるか
- BoxView→透明Buttonに置き換えると止まるか
- 背面側をIsEnabled=falseにすると止まるか
この比較で「BoxViewだけ貫通する」のか、「どのオーバーレイでも貫通する(別の要因)」のかが分かります。
それでも再現する場合:報告時に揃える情報
InputTransparent系は環境差が出やすいため、報告(社内共有でも、GitHubでも)では情報が揃っているほど解決が早いです。
- MAUIのバージョン(.NET SDK、Microsoft.Maui.Controls、ワークロード)
- AndroidのOSバージョン、端末名、再現する/しない端末の差
- 最小再現プロジェクト(1ページで再現できる形)
- 「BoxViewだけ」なのか、「他の要素でも」なのかの比較結果
既に類似のIssueがある場合も、あなたの再現条件が異なるなら新規スレッドとして整理した方が、修正が入りやすくなります(Microsoft Q&Aでも“新しいスレッドで最小再現を”という誘導が見られます)。
まとめ:おすすめの結論(迷ったらこれ)
- BoxViewのInputTransparentでタップを止める設計は、Androidで既知不具合に当たることがある(過去のIssue、近年のBoxView特化Issueも存在)
- まずはMAUIを新しい系統へ更新し、改善するか確認する(InputTransparent/CascadeInputTransparentの大きな修正が入っている)
- 更新が難しい、または再現が残るなら、背面をIsEnabled=falseで止めるのが最も堅牢
- オーバーレイで止めたい場合は、BoxViewではなくButtonやContentView+Gestureで“確実に入力を取る”方向へ寄せると事故が減る

コメント