Ксамарин.Формы-как наложить ActivityIndicator в середине StackLayout программно



Я хочу наложить свой ActivityIndicator в середине моей формы, но я не совсем уверен, как я могу это сделать, я предполагаю, что мне нужно обернуть мой макет стека в относительный макет ?



Я делаю это в коде, и ближайший пример, который я нашел, - это использование XAML, который использует сетку, как показано ниже:



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

6 ответов:

Если у вас есть проблемы с RelativeLayout, вы также можете использовать AbsoluteLayout, который работает в аналогичном контексте. Пример кода ниже:

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

Если вам нужен полный рабочий пример, я сделал его доступным @ https://github.com/teamtam/xamarin-forms-timesheet

Приемлемый ответ, но я написал расширения для всех страниц контента. Я думаю, это было бы неплохо.

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;
    }
Замечание: IsWorking должен быть членом свойства ViewModel (implementedINotifyProppertyChanged ).

Вызов страницы расширения ctor последнее утверждение.

this.AddProgressDisplay();

Вам нужно использовать абсолютную компоновку. Следуйте следующей иерархии макета:

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

При этом индикатор активности будет наложен в середине макета стека.

Да.. Вы должны обернуть свой stacklayout внутри относительной компоновки.. Я уже прошел через пример, который вы привели, и достиг моего требования, форматируя мой XAML, как показано ниже кода

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> 

В коде вы можете попробовать следующее:

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

Предполагая ширину / высоту индикатора ActivityIndicator 32/32, вы можете выбрать размер, который соответствует вашим потребностям, или вычислить размер на лету.

Похоже, что в RelateiveLayout все еще есть ошибки, он иногда выдает неожиданные исключения нулевого указателя, даже для разрешимых ограничений

Вы также можете использовать индикатор активности внутри абсолютного макета. и свяжите свойство isVisible абсолютной компоновки с isBusy. Ниже приведен мой подход

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

Привязка в cs-файле выглядит как

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

Comments

    Ничего не найдено.