question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InputTransparent logic/intended behavior

See original GitHub issue

Description

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:open
  • Created a year ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
emceelovincommented, May 26, 2022

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.

1reaction
hartezcommented, May 26, 2022

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 to false. 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 property CascadeInputTransparent, which is a holdover from Xamarin.Forms. It defaults to true, and it just means that if you mark a Layout as InputTransparent = true, then every control inside of that Layout will also be effectively input transparent. If you disable CascadeInputTransparent 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 the CascadeInputTransparent 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.

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.

Your assumption is correct - if CascadeInputTransparent = true and InputTransparent = 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.

Is trying to double tap a ListView item bad design/practice when choosing an item?

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?

Read more comments on GitHub >

github_iconTop Results From Across the Web

InputTransparent logic/intended behavior · dotnet/maui@d6bc1ca
... a framework for building native device applications spanning mobile, tablet, and desktop. - InputTransparent logic/intended behavior · dotnet/maui@d6bc1ca.
Read more >
VisualElement.InputTransparent Property (Xamarin.Forms)
Gets or sets a value indicating whether this element should be involved in the user interaction cycle. This is a bindable property.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found