No desenvolvimento de interfaces de usuário, normalmente precisamos manipular elementos de tela dinamicamente de acordo com alguma ação do usuário, seja enviar um formulário, rotacionar um dispositivo, ou mesmo algum comportamento previsto em nossa regra de negócio. Foi pensando nestes e em outros cenários que a equipe de desenvolvimento do Xamarin Forms desenvolveu o Visual State Manager.

O que é o Visual State Manager

Uma das novidades da versão 3.+ do Xamarin Forms é o Visual State Manager. O Visual State Manager é um recurso que foi integrado ao Xamarin Forms e oferece a pessoa desenvolvedora uma forma de trabalhar os estados das interfaces de usuário desenvolvidas em XAML dinamicamente. Ele é capaz de personalizar estilos dos objetos como background, font-color, font-size, visibility entre outros.

O Visual State Manager ou VSM é composto com Visual States. São os Visual States que irão definir estilos para os objetos de tela do Xamarin Forms. Um Visual State irá atuar diretamente nas propriedades de um objeto como clique, focus, habilitado, desabilitado, landscape, portait e etc.

A definição de um Visual State é feita através de um Visual State Group. O Visual State Group é como um container de Visual States. Todos os Visual States definidos dentro de um Visual State Group são mutuamente exclusivos, o que significa que você não poderá ter um objeto que esteja em dois estados definidos dentro de um mesmo grupo de estados.

Todas as classes que derivam de VisualElement que é classe base para View e Page possuem suporte para a utilização do Visual State Manager.

Visual State Group

Visual Sate Group são os containers de estados visuais do Visual State Manager e também é com ele que setamos dentro de um Setter do Style que os styles definidos dentro desta tag sejam tratados como objetos do Visual State Manager . É dentro das tags do Visual State Group que vamos adicionar os Visual States que desejamos que nosso app contenha.

Visual States

Visual States são os estados visual dos objetos. É dentro dele que vamos definir como um objeto deve ser personalizado de acordo com qual Visual State ele se encontra.

Common States

O Visual State Manager já possui alguns Visual States que são comuns para todos os objetos, eles são chamados de Common States, veja abaixo:

  • “Normal”
  • “Disabled”
  • “Focus”

Isto significa que o State já existem, mas você precisará descrever os estilos a serem aplicados quando o elemento estiver neste estado. O que muda dos common states para o custom states, que veremos a frente, é que você não precisará programar no backend da tela para que o estado seja aplicado, você poderá “triga-lo” diratamente na tela tratando a propriedade do objeto.

Custom States

Como as validações que precisamos no nosso front não se restringem apenas aos estados Normal, Disabled e Focus, o Visual State Manager suporta a criação dos Visual States customizados.

Eles seguem o mesmo principio de criação de um Common State e também deve estar dentro de um Visual State Group. A diferença aqui é que você irá setar o estado no seu objeto através de um código C# no backend da tela.

Onde definir meus Visual States?

Você pode definir os visual states do seu app de 3 maneiras.

Você incluir os visual states dentro do próprio objeto de tela para que ele tenha efeito para apenas aquele objeto. Então imagine que quero que apenas um Label da minha tela tenha um Visual State específico, o Visual State seria adicionado dentro das tags de <Label> e </Label>

Uma outra maneria de definir os Visual States é dentro dos Resources da página. Nesta forma de definição você irá criar os Visual States dentro de uma tag Style com o Target Type setado para o tipo de objeto que deseja tratar e todos os objetos deste tipo dentro desta página poderão ser afetados pelo Visual State.

Uma terceira forma é você definir todos os seus Visual States dentro da App.xaml.cs. Esta forma de definição é semelhante a definida acima (dentro dos Resources e em tag Style), entretanto o efeito destes Visual States poderão ser aplicados em todas as páginas da aplicação.

Validando um formulário com Visual State Manager

Para exemplificar o uso do Visual State Manager, vamos criar um formulário utilizando Xamarin Forms e submetê-lo através de um botão.

Para concluir esta demo, você precisará estar utilizando a versão 3.0 ou superior do Xamarin Forms para que tudo funcione corretamente.

Criando o formulário

Vamos criar um novo projeto Xamarin Forms no Visual Studio (verifique se o versão do forms instalada no seu projeto é a 3.0 ou superior).

Na própria MainPage.xaml que foi criada automaticamente, vamos adicionar um formulário básico:

<StackLayout Margin="10">
    <Label Text="Nome"/>
    <Entry x:Name="Nome" />
    <Label x:Name="NomeMsg" Style="{StaticResource ValidationMessage}" Text="O campo nome é obrigatório."/>
    
    <Label Text="E-mail"/>
    <Entry x:Name="Email" />
    <Label x:Name="EmailMsg" Style="{StaticResource ValidationMessage}" Text="Informe um e-mail válido."/>
    
    <Label Text="Senha"/>
    <Entry IsPassword="True" x:Name="Senha" />
    <Label x:Name="SenhaMsg" Style="{StaticResource ValidationMessage}" Text="A senha deve conter 6 caracteres ou mais."/>

    <Button Text="Enviar" VerticalOptions="EndAndExpand" />
</StackLayout>

Observe que criamos três mensagens de alerta que serão exibidas ao preencher o formulário. Estas mensagens estão personalizadas com o estilo ValidationMessage. Vamos adicionar o estilo na página:

<Style x:Key="ValidationMessage" TargetType="Label">
    <Setter Property="FontSize" Value="Micro"/>
    <Setter Property="FontAttributes" Value="Italic"/>
</Style>

Para que o formulário fique interativo com o usuário enquanto ele preenche os dados, vamos adicionar eventos de text change nos campos Entry para que, ao preencher o formulário, o usuário já saiba se as informações preenchidas estão suprindo os requerimentos de validação de dados ou não. Vamos também adicionar o evento de clique no botão para enviar o formulário. Após adicionar os eventos o formulário ficará assim:

<StackLayout Margin="10">
    <Label Text="Nome"/>
    <Entry x:Name="Nome" TextChanged="Nome_TextChanged"/>
    <Label x:Name="NomeMsg" Style="{StaticResource ValidationMessage}" Text="O campo nome é obrigatório."/>
    
    <Label Text="E-mail"/>
    <Entry x:Name="Email" TextChanged="Email_TextChanged"/>
    <Label x:Name="EmailMsg" Style="{StaticResource ValidationMessage}" Text="Informe um e-mail válido."/>
    
    <Label Text="Senha"/>
    <Entry IsPassword="True" x:Name="Senha" TextChanged="Senha_TextChanged"/>
    <Label x:Name="SenhaMsg" Style="{StaticResource ValidationMessage}" Text="A senha deve conter 6 caracteres ou mais."/>

    <Button Text="Enviar" VerticalOptions="EndAndExpand" Clicked="Button_Clicked" />
</StackLayout>

Após criado o formulário e adicionado os eventos, é hora de criar os Visual State Group e Visual States para página.

Criando o Visual State Group e Visual States

Em ContentPage.Resources, vamos adicionar o Visual State que irá tratar o estado dos Entrys da tela de formulários:

<Style TargetType="Entry">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="ValidationStates">
                <VisualState x:Name="Valid">
                    <VisualState.Setters>
                        <Setter Property="TextColor" Value="Black"/>
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Invalid">
                    <VisualState.Setters>
                        <Setter Property="TextColor" Value="Red"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

Como a ideia deste Visual State Group é tratar apenas dos Entry desta tela, o conteúdo dele foi adicionado dentro de uma tag Style do tipo Entry dos Resources desta Page.

Perceba que primeiro adicionamos um Setter dentro da tag Style setada para Entry com a propriedade VisualStateManager.VisualStateGroups, isto irá informar para o Xamarin Forms que tudo que estiver dentro desta tag trata-se de conteúdo do Visual State Manager. Seguindo, adicionamos uma tag Visual State Group List e adicionamos uma tag Visual State Group com o nome de ValidationStates. É dentro desta tag que iremos adicionar todos os states que queremos que nossos objetos de tela tenham.

Adicionamos uma tag Visual State com o nome Valid que será responsável por personalizar os objetos de tela quando eles estiverem válidos. Dentro dele adicionamos os Setters que agirão como os Style que já conhecemos na personalização de objetos.

Veja que adicionamos também mais um State, o Invalid, que irá personalizar os objetos quando estiverem inválidos. Dentro dele também adicionamos os Setters do estilo que queremos.

Agora, vamos adicionar os States da mensagem de alerta que adicionamos no formulário. Estes Visual States serão adicionados dentro de uma nova tag Style porque irão customizar Labels desta página, e não mais Entrys como nos Visual States anteriores.

<Style x:Key="ValidationMessage" TargetType="Label">
    <Setter Property="FontSize" Value="Micro"/>
    <Setter Property="FontAttributes" Value="Italic"/>
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="ValidationStates">
                <VisualState x:Name="Normal">
                    <VisualState.Setters>
                        <Setter Property="IsVisible" Value="False"/>
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Valid">
                    <VisualState.Setters>
                        <Setter Property="IsVisible" Value="False"/>
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Invalid">
                    <VisualState.Setters>
                        <Setter Property="IsVisible" Value="True"/>
                        <Setter Property="TextColor" Value="Red"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

Uma observação importante aqui é que incrementamos o estilo adicionado anteriormente que apenas personalizava de forma estática a mensagem de alerta. Agora, o estilo da mensagem de alerta contém estados que personalizarão a mensagem de forma dinâmica.

Validando o formulário

Após adicionarmos os Visual States na nossa Page, vamos agora falar para o Xamarin Forms quando eles devem ser executados e em quais condições.

Os Visual States customizados, serão trigados no backend da página quando o evento de Text Change acontecer (lembre-se que já adicionamos este evento nos entrys do formulário), para isto, vamos adicionar um método que sabe validar se cada entry está com a informação esperada. Em MainPage.xaml.cs vamos adicionar os métodos:

private bool ValidarNomeDoUsuario()
{
    var isValid = (Nome.Text ?? "").Length > 0;

    var state = isValid ? "Valid" : "Invalid";

    VisualStateManager.GoToState(Nome, state);
    VisualStateManager.GoToState(NomeMsg, state);

    return isValid;
}

private bool ValidarEmailInformado()
{
    var isValid = Email.Text.Contains("@");

    var state = isValid ? "Valid" : "Invalid";

    VisualStateManager.GoToState(Email, state);
    VisualStateManager.GoToState(EmailMsg, state);

    return isValid;
}

private bool ValidarSenhaInformada()
{
    var isValid = Senha.Text.Length > 6;

    var state = isValid ? "Valid" : "Invalid";

    VisualStateManager.GoToState(Senha, state);
    VisualStateManager.GoToState(SenhaMsg, state);

    return isValid;
}

Nos métodos acima utilizamos o método GoToState da classe VisualStateManager. Este método recebe o nome do objeto que tela no primeiro parâmetro (nome de um entry, label, button, etc). Observe que usamos o método uma vez passando o nome dos Entrys e uma outra vez passando o nome das Labels das mensagens de alerta. Já no segundo parâmetro o método recebe o Visual State que o objeto deve ser enviado.

Nestes métodos fizemos uma pequena lógica de exemplo para definir qual Visual State o objeto deveria ser enviado, se Valid ou Invalid.

Após adicionado os métodos que sabem validar os campos, vamos executa-los nos eventos de Text Change de cada Entry:

private void Nome_TextChanged(object sender, TextChangedEventArgs e)
{
    ValidarNomeDoUsuario();
}

private void Email_TextChanged(object sender, TextChangedEventArgs e)
{
    ValidarEmailInformado();
}

private void Senha_TextChanged(object sender, TextChangedEventArgs e)
{
    ValidarSenhaInformada();
}

Por fim vamos tratar o evento de clique do botão enviar do formulário. Para que ele também valide as informações, vamos adicionar mais um método que executa os métodos validadores que criamos acima:

private void Button_Clicked(object sender, EventArgs e)
{
    if (IsValid())
        DisplayAlert("rsamorim", "Você foi registrado com sucesso!", "OK");
    else
        DisplayAlert("rsamorim", "Por favor, verifique os campos informados.", "OK");
}

bool IsValid()
{
    var nomeValid = ValidarNomeDoUsuario();
    var emailValid = ValidarEmailInformado();
    var senhaValid = ValidarSenhaInformada();

    return nomeValid && emailValid && senhaValid;
}

Feito tudo isto, o formulário já está preparado para ser executado e validar as informações do usuário utilizando o Visual State Manager. Execute o app e veja se tudo ocorreu como esperado.

Conclusão

A inclusão do recurso Visual State Manager ao Xamarin Forms é bastante interessante pois flexibiliza e facilita o trabalho do desenvolvedor na personalização de objetos de tela de acordo com a regra de negócio e as necessidades do aplicativo. Basicamente ele é um forma de se escrever Styles para o App que são executados dinamicamente.

Você pode ler mais sobre o Visual State Manager neste endereço.

Você pode baixar o código fonte deste post no meu GitHub.

 

E aí, o que achou? Já utilizou o VSM em algum app?

#Ubuntu

 

Foto utilizada no post Pixabay

(Cross-post de http://rsamorim.azurewebsites.net/2018/08/13/xamarin-forms-formularios-iterativos-com-visual-state-manager/)