web-dev-qa-db-fra.com

Xamarin.Forms - Comment superposer un ActivityIndicator au milieu d'un StackLayout par programme

Je veux superposer mon ActivityIndicator au milieu de mon formulaire, mais je ne suis pas tout à fait sûr de savoir comment y parvenir. Je suppose que je dois envelopper la disposition de la pile dans une disposition relative? 

Je le fais dans le code et l'exemple le plus proche que j'ai trouvé utilise XAML qui utilise une grille comme indiqué ci-dessous: 

 <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>
25
Chad Bonthuys

Si vous avez des problèmes avec RelativeLayout, vous pouvez également utiliser AbsoluteLayout qui fonctionne dans un contexte similaire. Exemple de code ci-dessous:

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 vous souhaitez un exemple complet, j’en ai mis un disponible @ https://github.com/teamtam/xamarin-forms-timesheet

22
TeamTam

accpetable réponse mais j’ai écrit une extension pour toute page de contenu. Je pense que ça pourrait être 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;
    }

Remarque: IsWorking doit être membre de la propriété ViewModel (implémentée INotifyProppertyChanged ).

Appelez la dernière déclaration de la page d'extension ctor.

this.AddProgressDisplay();
10
Nuri YILMAZ

Vous devez utiliser une mise en page absolue. Suivez la hiérarchie suivante de la mise en page:

    <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>

Avec cela, l'indicateur d'activité sera superposé au milieu d'une pile.

6
Himanshu Dwivedi

Oui .. Vous devriez envelopper votre stacklayout dans la disposition relative .. J'ai déjà parcouru l'exemple que vous avez donné et satisfait à mon exigence en formatant mon code XAML comme ci-dessous

Code 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> 
6
Femil Shajin

Voici une version un peu plus personnalisable de la version de Nuri YILMAZ.

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;
        }
0
sajmons

Vous pouvez également utiliser un indicateur d'activité dans la mise en page absolue. et liez la propriété isVisible de layout absolue à isBusy. Ci-dessous mon approche

<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>

La liaison dans le fichier cs ressemble à

        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);
0
AbdulBasit

Dans CODE, vous pouvez essayer ceci:

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)));

En supposant la largeur/hauteur de l'ActivityIndicator 32/32, vous pouvez choisir une taille qui vous convient ou en calculer la taille à la volée.

Il semble toujours y avoir des bogues dans RelateiveLayout, il génère parfois des exceptions inattendues de pointeur null, même pour des contraintes résolvables.

0
Sten Petrov