maui

Can .NET MAUI have a transparent overlay that ignores events but has a child button which accepts events?


We have an overlay on top of our active content which contains a button. We would like the button to be active while events occurring in the rest of the overlay are passed to the active content behind.

The hierarchy looks like

[App]
  [Window]
    [NavigationPage]
      [OurPage]
        [Grid]
          ActiveContent[StackLayout]
            [ContentView]
          Overlay[ContentView]
            [Grid]
              OverlayButton[ImageButton]

We have tried toggling the InputTransparent property on the overlay, however, that means the overlay button within the overlay doesn't receive events. iOS has some hit test methods for views as well as methods for gesture recognizers that would allow this to work. Is there anything similar in .NET MAUI?


Solution

  • Is there anything similar in .NET MAUI?

    On maui, you can try to add TapGestureRecognizer to the overlay ContentView .

        <!--the overlay  -->
        <ContentView 
                 Grid.ColumnSpan="2"
                 Grid.RowSpan="3"
                 BackgroundColor="Transparent"
                 HorizontalOptions="FillAndExpand"
                 VerticalOptions="FillAndExpand">
            <ContentView.GestureRecognizers>
                <TapGestureRecognizer Tapped ="TapGestureRecognizer_Tapped" NumberOfTapsRequired="1"
                />
            </ContentView.GestureRecognizers>
    
            <Button  Clicked="Button_Clicked"
                    HeightRequest="60"  WidthRequest="100" />
        </ContentView>
    

    I created a demo and achieved the similar function, you can refer to the following code:

    MainPage.xaml

    <?xml version="1.0" encoding="utf-8" ?> 
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MauiTapApp411.MainPage">
    
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="100" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <BoxView Color="Green" />
            <Label Text="Row 0, Column 0"
                   HorizontalOptions="Center"
                   VerticalOptions="Center" />
            <BoxView Grid.Column="1"
                     Color="Blue" />
            <Label Grid.Column="1"
                   Text="Row 0, Column 1"
                   HorizontalOptions="Center"
                   VerticalOptions="Center" />
    
            <BoxView Grid.Row="1"
                     Color="Teal" />
            <Label Grid.Row="1"
                   Text="Row 1, Column 0"
                   HorizontalOptions="Center"
                   VerticalOptions="Center" />
    
            <BoxView Grid.Row="1"
                     Grid.Column="1"
                     Color="Purple" />
            <Button Grid.Row="1"
                   Grid.Column="1"
                   Text="Row1, Column 1"
                   HorizontalOptions="Center"
                   VerticalOptions="Center" />
    
            <!--the overlay  -->
            <ContentView 
                     Grid.ColumnSpan="2"
                     Grid.RowSpan="3"
                     BackgroundColor="Transparent"
                     HorizontalOptions="FillAndExpand"
                     VerticalOptions="FillAndExpand">
                <ContentView.GestureRecognizers>
                    <TapGestureRecognizer Tapped ="TapGestureRecognizer_Tapped" NumberOfTapsRequired="1"
                    />
                </ContentView.GestureRecognizers>
    
                <Button  Clicked="Button_Clicked"
                        HeightRequest="60"  WidthRequest="100" />
            </ContentView>
    
        </Grid>
    </ContentPage>
    

    MainPage.xaml.cs

    public partial class MainPage : ContentPage 
    {
          int count = 0;
    
          public MainPage()
          {
                InitializeComponent();
          }
    
        private  void Button_Clicked(object sender, EventArgs e)
        {
            doSomething();
        }
    
        private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
        {
            doSomething();
        }
        private async void doSomething() {
            await DisplayAlert("Alert", "You have been alerted", "OK");
        }
    }
    

    Note:

    From above code, you can try to listen to the tap event of the overlay contentview(e.g. TapGestureRecognizer_Tapped), and add the necessary code to the function TapGestureRecognizer_Tapped which is the same to the code added to the click event of the inner button.

    private  void Button_Clicked(object sender, EventArgs e)
        {
            doSomething();
        }
    
        private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
        {
            doSomething();
        }
        private async void doSomething() {
            await DisplayAlert("Alert", "You have been alerted", "OK");
        }