I want to overlay my ActivityIndicator in the middle of my form but I\'m not entirely sure how I can go about this, I assume I need to wrap my stack layout in a relative lay
You can also use activity indicator inside the absolute layout. and bind the isVisible property of absolute layout to isBusy. Below is my approach
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" AbsoluteLayout.LayoutBounds="1, 1, 1, 1"
BackgroundColor="White" Opacity="0.5" AbsoluteLayout.LayoutFlags="All" x:Name="indicatorFrame" IsVisible="false">
<ActivityIndicator x:Name="indicator" IsVisible="true" IsRunning="true" IsEnabled="true"
HorizontalOptions="Center" VerticalOptions="Center" AbsoluteLayout.LayoutBounds="1, 1, 1, 1"
Color="Black" AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
The binding in the cs file looks like
indicator.BindingContext = this;
indicator.SetBinding(IsVisibleProperty, "IsBusy", BindingMode.OneWay);
indicator.SetBinding(ActivityIndicator.IsRunningProperty, "IsBusy", BindingMode.OneWay);
indicatorFrame.BindingContext = this;
indicatorFrame.SetBinding(IsVisibleProperty, "IsBusy", BindingMode.OneWay);
There's an acceptable answer but I wrote an extensions for all contentpage and think it could be nice.
public static void AddProgressDisplay (this ContentPage page)
{
var content = page.Content;
var grid = new Grid();
grid.Children.Add(content);
var gridProgress = new Grid { BackgroundColor = Color.FromHex("#64FFE0B2"), Padding = new Thickness(50) };
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
gridProgress.SetBinding(VisualElement.IsVisibleProperty, "IsWorking");
var activity = new ActivityIndicator
{
IsEnabled = true,
IsVisible = true,
HorizontalOptions = LayoutOptions.FillAndExpand,
IsRunning = true
};
gridProgress.Children.Add(activity, 0, 1);
grid.Children.Add(gridProgress);
page.Content = grid;
}
Remark: IsWorking must be member of ViewModel (implemented INotifyPropertyChanged) property.
Call extension page ctor last statement.
this.AddProgressDisplay();
Here is a little more costumizable version of Nuri YILMAZ version.
public static void AddProgressDisplay(this ContentPage page, string isVisibleProperty = "IsBusy", string bgColor = "#1a1a1ab2")
{
var content = page.Content;
var grid = new Grid();
grid.Children.Add(content);
var gridProgress = new Grid { BackgroundColor = Color.FromHex(bgColor), Padding = new Thickness(50) };
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
gridProgress.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
gridProgress.SetBinding(VisualElement.IsVisibleProperty, isVisibleProperty);
var activity = new ActivityIndicator
{
IsEnabled = true,
IsVisible = true,
HorizontalOptions = LayoutOptions.FillAndExpand,
IsRunning = true
};
gridProgress.Children.Add(activity, 0, 1);
grid.Children.Add(gridProgress);
page.Content = grid;
}
Yes, you should wrap your StackLayout inside Relative Layout. I have already gone through the example which you have given and acheived my requirement by formatting my XAML as below code
XAML Code
<RelativeLayout ...>
<StackLayout ...>
<ActivityIndicator IsRunning="false"
Color="Maroon"
BackgroundColor="Black"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.28}" />
</StackLayout>
</RelativeLayout>
In code you can try this:
RelativeLayout relativeLayout = new RelativeLayout ();
StackLayout stack = new StackLayout ();
ActivityIndicator indicator = new ActivityIndicator ();
relativeLayout.Children.Add (stack);
relativeLayout.Children.Add (indicator);
RelativeLayout.SetBoundsConstraint (stack, () => relativeLayout.Bounds);
RelativeLayout.SetBoundsConstraint (indicator,
BoundsConstraint.FromExpression (() =>
new Rectangle (relativeLayout.Width / 2 - 16, relativeLayout.Height / 2 - 16, 32, 32)));
Assuming width/height of the ActivityIndicator of 32/32, you can pick a size that fits your needs or calculate the size on the fly.
There still seem to be bugs in RelateiveLayout, it throws unexpected null pointer exceptions on occasion, even for solvable constraints
If you have problems with RelativeLayout, you can also use AbsoluteLayout which works in a similar context. Sample code below:
var overlay = new AbsoluteLayout();
var content = new StackLayout();
var loadingIndicator = new ActivityIndicator();
AbsoluteLayout.SetLayoutFlags(content, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(content, new Rectangle(0f, 0f, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
AbsoluteLayout.SetLayoutFlags(loadingIndicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(loadingIndicator, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
overlay.Children.Add(content);
overlay.Children.Add(loadingIndicator);
If you would like a full working example, I have made one available @ https://github.com/teamtam/xamarin-forms-timesheet