LINQ2Vodka
LINQ2Vodka

Reputation: 3036

How to make ActivityIndicator overlay full screen?

I have a StackLayout and a number of elements inside (buttons, texts etc).
I want the ActivityIndicator to overlay the entire screen and make it not able to do anything to those elements.
I have put ActivityIndicator inside the StackLayout but wrapped it with AbsoluteLayout thinking that AbsoluteLayout can easitly overlap everything:

<StackLayout>
    <AbsoluteLayout>
        <ActivityIndicator ... />
    </AbsoluteLayout>
    <...other elements...> 
</StackLayout>

Instead activity indicator is displayed at the top of the StackLayout and other elements are available for affecting. I'm new in Xamarin and layouts, what am I doing wrong? All samples in the Internet have single ActivityIndicator per page...

Upvotes: 12

Views: 13078

Answers (3)

Here's a hacked-up control for making things full-screen via the horribly-named RelativeLayout (tested in Android only)

    [ContentProperty("ContentInner")]
    public class FullScreenLayout : ContentView
    {
        public View ContentInner
        {
            get => ((RelativeLayout) Content).Children[0];
            set
            {
                var display = DeviceDisplay.MainDisplayInfo;
                var screenWidth = display.Width / display.Density;
                var screenHeight = display.Height / display.Density;
                var wrapper = new RelativeLayout();
                wrapper.Children.Add(value, () => new Rectangle(0, 0, screenWidth, screenHeight));
                Content = wrapper;
            }
        }
    }

It can be used like this:

<controls:FullScreenLayout>
  <!-- Anything you want fullscreen here -->
</controls:FullScreenLayout>

Unfortunately, if you use NavigationPage, this won't overlap the navigation bar. Every other solution currently on this page has the same issue. According to this question, it's not possible to solve this without using platform-specific customer renderers. Ugh.

If you don't mind the page being dimmed, you can use Rg.Plugins.Popup which implements the custom renderers needed.


I ended up solving my similar problem (dimming most of the screen) by implementing a custom renderer for the navigation page itself.

Upvotes: 0

jgoldberger - MSFT
jgoldberger - MSFT

Reputation: 6088

It is better said that an AbsoluteLayout's children can easily overlap each other. Just as a StackLayout lets you stack controls inside , vertically or horizontally, an AbsoluteLayout lets you position controls inside using absolute or proportional values, thus if two controls have the same absolute positioning set, they will overlap 100%.

Therefore, you want to wrap your StackLayout and another StackLayout that has your ActivityIndicator inside an AbsoluteLayout using proportional sizing, e.g:

<AbsoluteLayout>
    <StackLayout
        x:Name="mainLayout"
        AbsoluteLayout.LayoutBounds="0,0,1,1"
                 AbsoluteLayout.LayoutFlags="All" >
        <Label Text="Welcome to Xamarin.Forms!"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
        <Button Text="Do Something"
                Clicked="DoSomethingBtn_Clicked" />
    </StackLayout>
    <StackLayout
        x:Name="aiLayout"
        IsVisible="False"
        AbsoluteLayout.LayoutBounds="0,0,1,1"
        AbsoluteLayout.LayoutFlags="All"
        BackgroundColor="Gray" Opacity="0.5">
        <ActivityIndicator
            x:Name="ai"
            IsRunning="False"
            HorizontalOptions="CenterAndExpand"
            VerticalOptions="CenterAndExpand"
            Color="Black"/>
    </StackLayout>

</AbsoluteLayout>

The above sets the two StackLayouts to both take up the full size of the parent container of the AbsoluteLayout, which is presumably a Page. The StackLayout that has the indicator is initially hidden. IN the page code behind for the above example, I show the second StackLayout and start the activity indicator and show it for 2 seconds, and then hide it again:

    private async void DoSomethingBtn_Clicked(object sender, EventArgs e)
    {
        ai.IsRunning = true;
        aiLayout.IsVisible = true;
        await Task.Delay(2000);
        aiLayout.IsVisible = false;
        ai.IsRunning = false;

    }

Here is what it looks like:

enter image description here

And since the second StackLayout completely covers the first, none of the controls in the first StackLayout are clickable.

Might be worth going over the docs for the AbsoluteLayout to understand the AbsoluteLayout.LayoutBounds and AbsoluteLayout.LayoutFlags: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/absolute-layout

Upvotes: 26

Rudy Spano
Rudy Spano

Reputation: 1421

If you want to "overlap", you need to be outside of the StackLayout. A Grid is the most common control for this:

<Grid>
  <StackLayout>
        <...other elements...> 
  </StackLayout>
  <ActivityIndicator ... />
</Grid>

Upvotes: 6

Related Questions