layoutoptions - Xamarin.Forms-Cómo superponer un ActivityIndicator en el medio de un StackLayout programáticamente
xamarin forms stacklayout alignment (6)
Quiero superponer mi ActivityIndicator en el medio de mi formulario, pero no estoy del todo seguro de cómo puedo hacerlo, supongo que tengo que ajustar el diseño de mi pila en un diseño relativo.
Estoy haciendo esto en código y el ejemplo más cercano que he encontrado es el uso de XAML que utiliza una cuadrícula como se ve a continuación:
<ScrollView BackgroundColor="#d3d6db">
<RelativeLayout
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Vertical"
VerticalOptions="FillAndExpand"
Padding="10"
RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}">
<Grid x:Name="SegmentGrid"
RowSpacing="10"
ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<WebView BackgroundColor="White" VerticalOptions="FillAndExpand" Source="{Binding DescriptionHtml}" />
</StackLayout>
<ActivityIndicator IsVisible="{Binding IsBusy}"
IsRunning="{Binding IsBusy}"
Color="Black"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}" />
</RelativeLayout>
</ScrollView>
En CODE puedes probar esto:
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)));
Asumiendo el ancho / alto del ActivityIndicator de 32/32, puede elegir un tamaño que se ajuste a sus necesidades o calcular el tamaño sobre la marcha.
Todavía parece haber errores en RelateiveLayout, arroja excepciones inesperadas de punteros nulos en ocasiones, incluso para restricciones solucionables
Necesitas usar el diseño absoluto. Siga la siguiente jerarquía del diseño:
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<!--< Your control design goes here >-->
</StackLayout>
<StackLayout IsVisible="{Binding IsBusy}" Padding="12"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
<ActivityIndicator IsRunning="{Binding IsBusy}" Color ="#80000000"/>
<Label Text="Loading..." HorizontalOptions="Center" TextColor="White"/>
</StackLayout>
</AbsoluteLayout>
Con esto, el indicador de actividad se superpondrá en el medio de un diseño de pila.
Sí. Debería envolver su diseño de pila en el diseño relativo ... Ya he analizado el ejemplo que me ha proporcionado y he logrado cumplir con mis requisitos formateando mi XAML como código a continuación.
Código XAML
<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>
Si tiene problemas con RelativeLayout, también puede utilizar AbsoluteLayout, que funciona en un contexto similar. Código de muestra a continuación:
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);
Si desea un ejemplo completo de trabajo, he hecho uno disponible @ https://github.com/teamtam/xamarin-forms-timesheet
También puede usar el indicador de actividad dentro del diseño absoluto. y enlaza la propiedad isVisible del diseño absoluto a isBusy. A continuación está mi enfoque
<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>
El enlace en el archivo cs se ve como
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);
respuesta aceptable, pero escribí una extensión para todas las páginas de contenido. Creo que podría ser bueno.
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;
}
Observación: IsWorking debe ser miembro de la propiedad ViewModel (implementado INotifyProppertyChanged ).
Llame a la página de extensión ctor última declaración.
this.AddProgressDisplay();