InputTransparent logic/intended behavior
See original GitHub issueDescription
InputTransparent logic seems to be incorrect/flawed, and I’d like to know which logic is correct, so that I don’t find out that “working” code is actually incorrect in the future. The docs don’t mention enough about InputTransparent IMO.
Given this code, the double tap gesture works(as expected?) on Windows, but it does not fall through the Label -> Grid -> ContentView -> ListView on Android, and this has been a thing since like, preview 12 or so. I brought it up in an issue a long time ago, so it’s really frustrating:
<!-- code for bidding:BidLineView-->
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="OneGreatTeam.Pages.Bidding.BidLineView"
CascadeInputTransparent="True">
<Grid RowDefinitions="auto"
Margin="0, 10, 0, 10"
ColumnDefinitions="*, *, *, *, *, *">
<Label Grid.Row="0"
Grid.Column="0"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding Line}"/>
<Label Grid.Row="0"
Grid.Column="1"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding Area}"/>
<Label Grid.Row="0"
Grid.Column="2"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding Duration}"/>
<Label Grid.Row="0"
Grid.Column="3"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding RDO}"/>
<Label Grid.Row="0"
Grid.Column="4"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding ALA}"/>
<Label Grid.Row="0"
Grid.Column="5"
TextColor="White"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding OSM}"/>
</Grid>
</ContentView>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:bidding="clr-namespace:OneGreatTeam.Pages.Bidding"
x:Class="OneGreatTeam.Pages.Bidding.BidPage"
Title="{OnIdiom Phone='Bid', Desktop=''}"
BackgroundColor="#18191A">
<Grid RowDefinitions="auto, *, auto"
ColumnDefinitions="*, *, *, *, *, *">
<Frame CornerRadius="10"
Padding="0"
Grid.Row="0"
Grid.Column="0"
BackgroundColor="Gray">
<Label Text="Line"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<Frame CornerRadius="10"
Padding="0, 5, 0, 5"
Grid.Row="0"
Grid.Column="1"
BackgroundColor="Gray">
<Label Text="Area"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<Frame CornerRadius="10"
Padding="0, 5, 0, 5"
Grid.Row="0"
Grid.Column="2"
BackgroundColor="Gray">
<Label Text="Hours"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<Frame CornerRadius="10"
Padding="0, 5, 0, 5"
Grid.Row="0"
Grid.Column="3"
BackgroundColor="Gray">
<Label Text="RDO"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<Frame CornerRadius="10"
Padding="0, 5, 0, 5"
Grid.Row="0"
Grid.Column="4"
BackgroundColor="Gray">
<Label Text="ALA"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<Frame CornerRadius="10"
Padding="0, 5, 0, 5"
Grid.Row="0"
Grid.Column="5"
BackgroundColor="Gray">
<Label Text="OSM"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</Frame>
<ListView Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="6"
SelectionMode="Single"
SelectedItem="{Binding SelectedLine}"
SeparatorVisibility="None"
ItemsSource="{Binding BidLines}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<bidding:BidLineView/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="2" Tapped="TapGestureRecognizer_Tapped" Command="{Binding LineSelectedCommand}"/>
</ListView.GestureRecognizers>
</ListView>
<Button Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="6"
IsVisible="{OnIdiom Phone=True, Desktop=False}"
Text="Select Line"/>
</Grid>
</ContentPage>
After reading the docs, what I thought was expected – and wanted – behavior on Windows, actually seems 100% incorrect, and Android is the correct behavior. Kind of. Views are not InputTransparent by default(according to MSDN), and children inherit this by default as well, BUT on Windows, when placing a TapGestureRecognizer on the ListView, input is falling through any descendent in the UI tree all the way up to the input gesture registered to it. This is completely against what the documentation mentions. Input should be blocked by any descendent in a tree unless InputTransparent=True. Which causes all the children to inherit this by default due to CascadeInputTransparency=True by default. On Android, input on the ListView is blocked unless you place the TapGestureRecognizer further down the tree and place it on the <bidding:BidLineView/>
. IMO, and according to the doc, this is still wrong. Input should be blocked by the Grid layout inside of <bidding:BidLineView/>
and its children on both Android and Windows. Input should be blocked by anything obstructing a UI element in the visual tree. Necessitating the need for InputTransparent/CascadeInputTransparent. Meaning, unless something is the very last element in the tree and/or unobstructred, it should not receive input unless the proper attributes are specified.
Also, when placing the TapGestureRecognizer on <bidding:BidLineView>
, ListView selection doesn’t work on the ListView anymore, but the tap gesture event is fired. It’s like whack-a-mole. Gain here lose there.
TapGestureRecognizer on ListView with <bidding:BidLineView InputTransparent="True">
causes Android to crash on a local device and the emulator. Windows is fine.
There really isn’t good documentation for input gesture recognition either. How deep does CascadeInputTransparent go? It says all children are affected. Does it end at the layout its specified on, or does it continue until the last child in the layouts visual tree? A layout can have layouts as children, so where does it end? If CascadeInputTransparent is True by default, then I would assume InputTransparent=True would mean it goes all the way until the last element in that node of the tree.
Windows: ContentPage -> Grid(Tap gesture recognized) -> ListView(Tap gesture recognized) -> bidding:BidLineView(Tap gesture recognized) Gestures shouldn’t be recognized at any of these places.
Android: ContentPage -> Grid(Nothing) -> ListView(Nothing) -> bidding:BidLineView(Tap gesture recognized/ListView item selection no longer works due to BidLineView intercepting the double tap gesture. Should be blocked by descendants inside BidLineView) Closer to what the docs mention as behavior, but BidLineView still shouldn’t receive any input.
According to the docs and input transparency, the <Label>'s inside of the Grid inside of BidLineView should block everything unless they have gestures registered on them or descendants have InputTransparency=“True”. Allowing input to bubble upwards.
Can anyone explain the design/blueprint behind input transparency in the UI tree? What are the constraints, what’s allowed, how it’s SUPPOSE to work, where it’s suppose to be placed, examples, etc. Been fighting this problem since the preview stages. All of this also happens with MVVM/Command’s. Which is what I actually run with non repro/sample code. Is trying to double tap a ListView item bad design/practice when choosing an item? My workaround, for now, is a Button on Phone/mobile. As Windows/desktop works the way I want it to. Keeping the tap gesture constrained to the main page, versus BidLineView, makes working with the pages ViewModel a lot easier and has proper UI functionality with highlighting and what not.
Steps to Reproduce
See xaml
Version with bug
6.0 (current)
Last version that worked well
Unknown/Other
Affected platforms
Android
Affected platform versions
Android/Windows
Did you find any workaround?
Yes, had to create a button on Android in lieu of double tap gestures.
Relevant log output
No response
Issue Analytics
- State:
- Created a year ago
- Comments:12 (6 by maintainers)
Top GitHub Comments
Appreciate the response a ton, and I don’t mean to come off harsh at all. I just want to see MAUI succeed so much, and try to offer up as much repro as I can. Will get back when I’m free. Also, I deleted and moved the other issue.
There are two concepts to keep in mind here, and I’ll be the first to admit that the documentation is confusing/lacking on both. The first is “input transparency”, the second is “gesture bubbling”.
Views have a boolean property
InputTransparent
which defaults tofalse
. Views which are input transparent don’t respond to touches/clicks - the interaction effectively goes “through” them to whatever is behind them. MAUI Controls also has a Layout propertyCascadeInputTransparent
, which is a holdover from Xamarin.Forms. It defaults totrue
, and it just means that if you mark a Layout asInputTransparent = true
, then every control inside of that Layout will also be effectively input transparent. If you disableCascadeInputTransparent
and mark a Layout as input transparent, then the Layout itself will not take input, but the controls inside of it can.If you don’t mark the Layout as
InputTransparent = true
, then theCascadeInputTransparent
property has no effect. So in your example XAML above, nothing is input transparent.The second concept, “gesture bubbling”, refers to how gestures defined on parent controls interact with child controls. Say, for example, you have a Layout with a single Label in it. If you define a tap gesture on the Layout, the gesture will fire if you tap on the Label. The label does not have its own gesture, but it bubbles the input up to its parent. This is the behavior for controls which do no accept input of their own (e.g., Labels and Images). Controls which accept input (e.g., Entries and Editors) don’t bubble gestures up to their parent controls.
Your assumption is correct - if
CascadeInputTransparent = true
andInputTransparent = true
on a Layout, then everything contained in that Layout should be input transparent unless explicitly marked otherwise. If that’s not the case, then we likely have a bug.The underlying control for a ListView on Android is an Android ListView, which has its own selection built it - I wonder if you’re seeing a bad interaction with that. It’s also entirely possible that we missed something porting the gesture/selection code from Forms and you’re seeing a bug. Do your selection problems show up in the Repro.zip project you uploaded in this comment?