Compartilhar via


StateContainer

Mostrar uma exibição específica quando seu aplicativo está em um estado específico é um padrão comum de qualquer aplicativo móvel. Os exemplos variam da criação de exibições de carregamento à sobreposição na tela ou em uma subseção dela. Exibições de estado vazias podem ser criadas para quando não há dados a serem exibidos e exibições de estado de erro podem ser mostradas quando ocorre um erro.

Introdução

As propriedades anexadas StateContainer permitem que o usuário transforme qualquer elemento de layout como um VerticalStackLayout, HorizontalStackLayout ou Grid em um layout com reconhecimento de estado. Cada layout com reconhecimento de estado contém uma coleção de elementos derivados de View. Esses elementos podem ser usados como modelos para diferentes estados definidos pelo usuário. Sempre que a propriedade de cadeia de caracteres CurrentState for definida como um valor que corresponda à propriedade StateKey de um dos elementos View, o conteúdo dela será exibido em vez do conteúdo principal. Quando CurrentState é definido como null ou como uma cadeia de caracteres vazia, o conteúdo principal é exibido.

Observação

Ao usar StateContainer com uma Grid, qualquer estados definido nele abrangerá automaticamente todas as linhas e colunas da Grid.

Sintaxe

As propriedades StateContainer podem ser usadas em XAML ou C#.

XAML

Incluir o namespace XAML

Para usar o kit de ferramentas no XAML, o xmlns a seguir precisa ser adicionado à sua página ou exibição:

xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"

Portanto, o seguinte:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

</ContentPage>

Seria modificado para incluir o xmlns conforme o seguinte:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

</ContentPage>

Como usar o StateContainer

Veja abaixo um exemplo de interface do usuário criado com o XAML. Este exemplo de interface do usuário está conectado ao ViewModel abaixo, StateContainerViewModel.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MyProject.MyStatePage"
             BindingContext="StateContainerViewModel">

    <VerticalStackLayout 
        toolkit:StateContainer.CurrentState="{Binding CurrentState}"
        toolkit:StateContainer.CanStateChange="{Binding CanStateChange}">

        <toolkit:StateContainer.StateViews>
            <VerticalStackLayout toolkit:StateView.StateKey="Loading">
                <ActivityIndicator IsRunning="True" />
                <Label Text="Loading Content..." />
            </VerticalStackLayout>
            <Label toolkit:StateView.StateKey="Success" Text="Success!" />
        </toolkit:StateContainer.StateViews>

        <Label Text="Default Content" />
        <Button Text="Change State" Command="{Binding ChangeStateCommand}" />

    </VerticalStackLayout>

</ContentPage>

Markup do C#

Abaixo está a mesma interface do usuário que o XAML criou acima usando a Marcação C#.

Este exemplo de interface do usuário está conectado ao ViewModel abaixo, StateContainerViewModel.

using CommunityToolkit.Maui.Layouts;
using CommunityToolkit.Maui.Markup;

BindingContext = new StateContainerViewModel();

Content = new VerticalStackLayout()
{
    new Label()
        .Text("Default Content"),
    
    new Button()
        .Text("Change State")
        .Bind(
            Button.CommandProperty,
            static (StateContainerViewModel vm) => vm.ChangeStateCommand,
            mode: BindingMode.OneTime)
}.Bind(
    StateContainer.CurrentStateProperty,
    static (StateContainerViewModel vm) => vm.CurrentState,
    static (StateContainerViewModel vm, string currentState) => vm.CurrentState = currentState)
 .Bind(
    StateContainer.CanStateChange,
    static (StateContainerViewModel vm) => vm.CanStateChange,
    static (StateContainerViewModel vm, bool canStateChange) => vm.CanStateChange = canStateChange)
 .Assign(out VerticalStackLayout layout);

var stateViews = new List<View>()
{
    //States.Loading
    new VerticalStackLayout()
    {
        new ActivityIndicator() { IsRunning = true },
        new Label().Text("Loading Content")
    },

    //States.Success
    new Label().Text("Success!")
};

StateView.SetStateKey(stateViews[0], States.Loading);
StateView.SetStateKey(stateViews[1], States.Success);

StateContainer.SetStateViews(layout, stateViews);

static class States
{
    public const string Loading = nameof(Loading);
    public const string Success = nameof(Success);
}

ViewModel

Ao usar um ICommand para alterar CurrentState (por exemplo, ao usar Button.Command para alterar estados), recomendamos usar CanStateBeChanged para ICommand.CanExecute().

Veja abaixo um exemplo do MVVM com o Kit de Ferramentas da Comunidade do MVVM:

[INotifyPropertyChanged]
public partial class StateContainerViewModel
{
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(ChangeStateCommand))]
    bool canStateChange;

    [ObservableProperty]
    string currentState = States.Loading;

    [RelayCommand(CanExecute = nameof(CanStateChange))]
    void ChangeState()
    {
        CurrentState = States.Success;
    }
}

Por padrão, StateContainer altera o estado sem animação. Para adicionar uma animação personalizada, use o método ChangeStateWithAnimation:

async Task ChangeStateWithCustomAnimation()
{
    var targetState = "TargetState";
    var currentState = StateContainer.GetCurrentState(MyBindableObject);
    if (currentState == targetState)
    {
        await StateContainer.ChangeStateWithAnimation(
            MyBindableObject,
            null,
            (element, token) => element.ScaleTo(0, 100, Easing.SpringIn).WaitAsync(token),
            (element, token) => element.ScaleTo(1, 250, Easing.SpringOut).WaitAsync(token),
            CancellationToken.None);
    }
    else
    {
        await StateContainer.ChangeStateWithAnimation(
            MyBindableObject,
            targetState,
            (element, token) => element.ScaleTo(0, 100, Easing.SpringIn).WaitAsync(token),
            (element, token) => element.ScaleTo(1, 250, Easing.SpringOut).WaitAsync(token),
            CancellationToken.None);
    }
}

É assim que ele funciona no iOS:

StateContainer Animation

Propriedades

StateContainer

As propriedades StateContainer podem ser usadas em qualquer elemento herdado Layout.

Propriedade Type Descrição
StateViews IList<View> Os elementos View disponíveis a serem usados como modelos de estado.
CurrentState string Determina qual elemento View com a StateKey correspondente deve ser exibido.

Aviso: CurrentState não pode ser alterado enquanto uma alteração de estado está em andamento
CanStateChange bool Quando ele for true, a propriedade CurrentState poderá ser alterada. Quando ele for false, ela não poderá ser alterada porque ela está sendo alterada no momento.

Aviso: se CurrentState for alterado quando CanStateChanged for false, uma StateContainerException será gerada.

StateView

As propriedades StateView podem ser usadas em qualquer elemento herdado View.

Propriedade Type Descrição
StateKey string Nome do estado.

Métodos

StateContainer

Método Argumentos Descrição
ChangeStateWithAnimation (estático) BindableObject bindable, string? state, Animation? beforeStateChange, Animation? afterStateChange, CancellationToken token Altera o estado com uma animação personalizada.
ChangeStateWithAnimation (estático) BindableObject bindable, string? state, Func<VisualElement, CancellationToken, Task>? beforeStateChange, Func<VisualElement, CancellationToken, Task>? afterStateChange, CancellationToken cancellationToken Altera o estado com uma animação personalizada.
ChangeStateWithAnimation (estático) BindableObject bindable, string? state, CancellationToken token Altera o estado usando a animação de abertura gradual padrão.

Exemplos

Encontre um exemplo desse recurso em ação no Aplicativo de exemplo do Kit de Ferramentas da Comunidade do .NET MAUI.

API

O código-fonte do StateContainer pode ser encontrado no repositório GitHub do .NET MAUI Community Toolkit.