AbsoluteLayout controls on a modal page only position horizontally in .NET MAUI

141 views Asked by At

Is there any way to position an AbsoluteLayout control on the center of the screen, or at least on the center of the page as an overlay, on a modal page? Is this possible in any way or why does this not work as expected? Using MAUI Community Toolkit I could create a Popup as an overlay but this obviously has a lot of limitations!

Here's my example page:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.ModalPage"
             Shell.PresentationMode="ModalAnimated"
             BackgroundColor="#55000000">
    <StackLayout VerticalOptions="End">
        <Frame Style="{StaticResource PopupFrameModal}"
               StyleClass="PopupFrame"
               BackgroundColor="White"
               BorderColor="White"
               HeightRequest="256"
               Margin="0,0,0,-24" CornerRadius="24">
            <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
                <StackLayout HorizontalOptions="Center">
                    <BoxView HeightRequest="10" WidthRequest="100" CornerRadius="5"/>
                    <BoxView HeightRequest="1" Margin="0,18,0,24"/>
                    <VerticalStackLayout>
                        <Label Text="This is a modal page" HorizontalOptions="Center"/>
                    </VerticalStackLayout>
                </StackLayout>
                <AbsoluteLayout>
                    <ActivityIndicator AbsoluteLayout.LayoutFlags="PositionProportional"
                                       AbsoluteLayout.LayoutBounds="0.5,0.5"
                                       Margin="0,16,0,0"
                                       IsVisible="True"
                                       IsRunning="True"/>
                </AbsoluteLayout>
            </StackLayout>
        </Frame>
        <!-- Could also be placed here, but 
             the indicator will show up below 
             the modal page instead... -->
    </StackLayout>
</ContentPage>

In this example the control that I used a simple <ActivityIndicator> for the <AbsoluteLayout>. It could be anything more complex. The indicator only centers horizontally. Vertically it behaves like a relatively positioned control, also when setting properties such as margins. Notice the Shell.PresentationMode="ModalAnimated" prop that I used for the <ContentPage>.

1

There are 1 answers

2
Julian On BEST ANSWER

If your AbsoluteLayout is a child of a StackLayout, then it won't necessarily be in the center of the ContentPage, because you're telling it to be stacked vertically below other visual elements.

If you want the AbsoluteLayout to overlay everything else, it should not be a child of the StackLayout, but instead it should be on the same hierarchical level as the StackLayout but with a higher z-index.

You could achieve this, for example, by wrapping the StackLayout and the AbsoluteLayout in a Grid, which is commonly used for stacking in z-direction:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.ModalPage"
             Shell.PresentationMode="ModalAnimated"
             BackgroundColor="#55000000">
    <Grid>
        <StackLayout VerticalOptions="End">
            <Frame Style="{StaticResource PopupFrameModal}"
                   StyleClass="PopupFrame"
                   BackgroundColor="White"
                   BorderColor="White"
                   HeightRequest="256"
                   Margin="0,0,0,-24" CornerRadius="24">
                <StackLayout HorizontalOptions="Center">
                    <BoxView HeightRequest="10" WidthRequest="100" CornerRadius="5"/>
                    <BoxView HeightRequest="1" Margin="0,18,0,24"/>
                    <VerticalStackLayout>
                        <Label Text="This is a modal page" HorizontalOptions="Center"/>
                    </VerticalStackLayout>
                </StackLayout>                
            </Frame>
        </StackLayout>
        <AbsoluteLayout VerticalOptions="Fill"
                        HorizontalOptions="Fill">
            <ActivityIndicator AbsoluteLayout.LayoutFlags="PositionProportional"
                               AbsoluteLayout.LayoutBounds="0.5,0.5"
                               Margin="0,16,0,0"
                               IsVisible="True"
                               IsRunning="True"/>
        </AbsoluteLayout>
    </Grid>    
</ContentPage>

However, this shouldn't even be necessary. For the purpose of showing an ActivityIndicator in the center of the page, you can simply place the ActivityIndicator directly into the center of the Grid, on top of the StackLayout (in z-direction) like this:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.ModalPage"
             Shell.PresentationMode="ModalAnimated"
             BackgroundColor="#55000000">
    <Grid>
        <StackLayout VerticalOptions="End">
            <Frame Style="{StaticResource PopupFrameModal}"
                   StyleClass="PopupFrame"
                   BackgroundColor="White"
                   BorderColor="White"
                   HeightRequest="256"
                   Margin="0,0,0,-24" CornerRadius="24">
                <StackLayout HorizontalOptions="Center">
                    <BoxView HeightRequest="10" WidthRequest="100" CornerRadius="5"/>
                    <BoxView HeightRequest="1" Margin="0,18,0,24"/>
                    <VerticalStackLayout>
                        <Label Text="This is a modal page" HorizontalOptions="Center"/>
                    </VerticalStackLayout>
                </StackLayout>                
            </Frame>
        <ActivityIndicator 
            HorizontalOptions="Center"
            VerticalOptions="Center"
            Margin="0,16,0,0"
            IsVisible="True"
            IsRunning="True"/>
    </Grid>    
</ContentPage>