Estados visuais
O Gerenciador de Estado Visual da interface do usuário do aplicativo .NET multiplataforma (.NET MAUI) fornece uma maneira estruturada de fazer alterações visuais na interface do usuário a partir do código. Na maioria dos casos, a interface do usuário de um aplicativo é definida em XAML e esse XAML pode incluir marcação que descreve como o Gerenciador de Estado Visual afeta os elementos visuais da interface do usuário.
O Gerenciador de Estado Visual apresenta o conceito de estados visuais. Uma exibição do .NET MAUI como um Button pode ter várias aparências visuais diferentes, dependendo de seu estado subjacente — se está desabilitado, pressionado ou tem foco de entrada. Estes são os estados do botão. Os estados visuais são coletados em grupos de estados visuais. Todos os estados visuais dentro de um grupo de estados visuais são mutuamente exclusivos. Os estados visuais e os grupos de estados visuais são identificados por cadeias de caracteres de texto simples.
O Gerenciador de Estado Visual do .NET MAUI define um grupo de estado visual chamado CommonStates
com os seguintes estados visuais:
- Normal
- Desabilitado
- Focalizado
- Selecionado
- PointerOver
Os estados visuais Normal
, Disabled
, Focused
e PointerOver
têm suporte em todas as classes derivadas de VisualElement, que é a classe base para View e Page. Além disso, você também pode definir seus próprios grupos de estado visual e estados visuais.
A vantagem de usar o Gerenciador de Estado Visual para definir a aparência, em vez de acessar elementos visuais diretamente do code-behind, é que você pode controlar como os elementos visuais reagem a um estado totalmente diferente no XAML, que mantém todo o design da interface do usuário em um único local.
Observação
Os gatilhos também podem fazer alterações em visuais na interface do usuário com base em alterações nas propriedades de um modo de exibição ou no acionamento de eventos. No entanto, usar gatilhos para lidar com várias combinações dessas mudanças pode se tornar confuso. Com o Gerenciador de Estado Visual, os estados visuais dentro de um grupo de estado visual são sempre mutuamente exclusivos. A qualquer momento, apenas um estado em cada grupo é o estado atual.
Estados visuais comuns
O Gerenciador de Estado Visual permite incluir marcação no arquivo XAML que pode alterar a aparência visual de um modo de exibição se o modo de exibição estiver normal, desabilitado, tiver foco de entrada, estiver selecionado ou estiver sendo focalizado pelo cursor, mas não pressionado. Estes são conhecidos como os estados comuns.
Por exemplo, suponha que você tenha um Entry modo de exibição em sua página e queira que a aparência visual do Entry mude das seguintes maneiras:
- O Entry deve ter um fundo rosa quando o Entry está desabilitado.
- O Entry deve ter um fundo limão normalmente.
- O Entry deve expandir para o dobro de sua altura normal quando tem foco de entrada.
- O Entry deve ter um plano de fundo azul claro quando o cursor do mouse estiver focalizando ele, mas não pressionando.
Você pode anexar a marcação do Gerenciador de Estado Visual a uma exibição individual ou defini-la em um estilo se ela se aplicar a várias exibições.
Definir estados visuais em um modo de exibição
A classe VisualStateManager
define uma propriedade VisualStateGroups
anexada, que é usada para anexar estados visuais a uma exibição. A propriedade VisualStateGroups
é do tipo VisualStateGroupList
, que é uma coleção de objetos VisualStateGroup
. Portanto, o filho da propriedade VisualStateManager.VisualStateGroups
anexada é um objeto VisualStateGroup
. Esse objeto define um atributo x:Name
que indica o nome do grupo. Como alternativa, a classe VisualStateGroup
define uma propriedade Name
que você pode usar. Para obter mais informações sobre propriedades anexadas, consulte Propriedades anexadas.
A classe VisualStateGroup
define uma propriedade chamada States
, que é uma coleção de objetos VisualState. States
é a propriedade de conteúdo da classe VisualStateGroups
para que você possa incluir os objetos VisualState como filhos do VisualStateGroup
. Cada objeto VisualState deve ser identificado usando x:Name
ou Name
.
A classe VisualState define uma propriedade chamada Setters
, que é uma coleção de objetos Setter. Esses são os mesmos objetos Setter que você usa em um objeto Style. Setters
não é a propriedade de conteúdo de VisualState, portanto, é necessário incluir marcas de elemento de propriedade para a propriedade Setters
. Objetos Setter devem ser inseridos como filhos de Setters
. Cada objeto Setter indica o valor de uma propriedade quando esse estado é atual. Qualquer propriedade com referência a um objeto Setter deve ser apoiada por uma propriedade vinculável.
Importante
Para que os objetos Setter de estado visual objetos funcionem corretamente, um VisualStateGroup
deve conter um objeto VisualState para o estado Normal
. Se esse estado visual não tiver nenhum objeto Setter, ele deverá ser incluído como um estado visual vazio (<VisualState Name="Normal" />
).
O exemplo a seguir mostra os estados visuais definidos em um Entry:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Entry>
A captura de tela a seguir mostra o Entry em seus quatro estados visuais definidos:
Quando o Entry está no estado Normal
, sua tela de fundo é limão. Quando o Entry obtém o foco de entrada, o tamanho da fonte dobra. Quando o Entry fica desabilitado, o plano de fundo fica rosa. O Entry não mantém seu plano de fundo limão quando ganha foco de entrada. Quando o ponteiro do mouse passa o mouse sobre o Entry, mas não é pressionado, o plano de fundo Entry fica azul claro. Como o Gerenciador de Estado Visual alterna entre os estados visuais, as definições das propriedades definidas pelo estado anterior são removidas. Portanto, os estados visuais são mutuamente exclusivos.
Se você quiser que o Entry tenha um plano de fundo limão no estado Focused
, adicione outro Setter a esse estado visual:
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
Definir estados visuais em um estilo
Geralmente, é necessário compartilhar os mesmos estados visuais em dois ou mais modos de exibição. Nesse cenário, os estados visuais podem ser definidos em um Style. Isso pode ser feito adicionando um objeto Setter à propriedade VisualStateManager.VisualStateGroups
. A propriedade de conteúdo do objeto Setter é sua propriedade Value
, que, portanto, pode ser especificada como o filho do objeto Setter. A propriedade VisualStateGroups
é do tipo VisualStateGroupList
e, portanto, o filho do objeto Setter é um VisualStateGroupList
ao qual um VisualStateGroup
pode ser adicionado que contém objetos VisualState.
O exemplo a seguir mostra um estilo implícito para um Entry que define os estados visuais comuns:
<Style TargetType="Entry">
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
Quando esse estilo for incluído em um dicionário de recursos no nível da página, o objeto Style será aplicado a todos os objetos Entry na página. Portanto, todos os objetos Entry na página responderão da mesma forma aos seus estados visuais.
Estados visuais no .NET MAUI
A tabela a seguir lista os estados visuais definidos no .NET MAUI:
Classe | Estados | Mais informações |
---|---|---|
Button | Pressed |
Estados visuais Button |
CarouselView | DefaultItem , CurrentItem , PreviousItem , NextItem |
Estados visuais CarouselView |
CheckBox | IsChecked |
Estados visuais CheckBox |
CollectionView | Selected |
Estados visuais CollectionView |
ImageButton | Pressed |
Estados visuais ImageButton |
RadioButton | Checked , Unchecked |
Estados visuais RadioButton |
Switch | On , Off |
Estados visuais Switch |
VisualElement | Normal , Disabled , Focused , PointerOver |
Estados comuns |
Definir o estado em vários elementos
Nos exemplos anteriores, os estados visuais eram anexados e operados em elementos únicos. No entanto, também é possível criar estados visuais anexados a um único elemento, mas que definem propriedades em outros elementos dentro do mesmo escopo. Isso evita ter que repetir estados visuais em cada elemento em que os estados operam.
O tipo Setter tem uma propriedade TargetName
do tipo string
, que representa o objeto de destino que o Setter para um estado visual manipulará. Quando a propriedade TargetName
é definida, o Setter define o Property
do objeto definido em TargetName
como Value
:
<Setter TargetName="label"
Property="Label.TextColor"
Value="Red" />
Neste exemplo, um Label nomeado label
terá sua propriedade TextColor
definida como Red
. Ao definir a propriedade TargetName
, você deve especificar o caminho completo para a propriedade em Property
. Portanto, para definir a propriedade TextColor
em um Label, Property
é especificado como Label.TextColor
.
Observação
Qualquer propriedade com referência a um objeto Setter deve ser apoiada por uma propriedade vinculável.
O exemplo a seguir mostra como definir o estado em vários objetos, de um único grupo de estado visual:
<StackLayout>
<Label Text="What is the capital of France?" />
<Entry x:Name="entry"
Placeholder="Enter answer" />
<Button Text="Reveal answer">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
<Setter TargetName="entry"
Property="Entry.Text"
Value="Paris" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
Neste exemplo, o estado Normal
está ativo quando o Button não é pressionado e uma resposta pode ser inserida no Entry. O estado Pressed
torna-se ativo quando o Button é pressionado e especifica que sua propriedade Scale
será alterada do valor padrão de 1 para 0,8. Além disso, o Entry nomeado como entry
terá sua propriedade Text
definida como Paris. Portanto, o resultado é que quando o Button é pressionado, ele é redimensionado para ser um pouco menor e Entry exibe Paris:
Em seguida, quando o Button é liberado, ele é redimensionado para seu valor padrão de 1 e Entry exibe qualquer texto inserido anteriormente.
Importante
Os caminhos de propriedade não têm suporte em elementos Setter que especificam a propriedade TargetName
.
Definir estados visuais personalizados
Os estados visuais personalizados podem ser implementados definindo-os como você definiria estados visuais para os estados comuns, mas com os nomes de sua escolha e chamando o método VisualStateManager.GoToState
para ativar um estado.
O exemplo a seguir mostra como usar o Gerenciador de Estado Visual para validação de entrada:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmValidationPage"
Title="VSM Validation">
<StackLayout x:Name="stackLayout"
Padding="10, 10">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">
<VisualState Name="Valid">
<VisualState.Setters>
<Setter TargetName="helpLabel"
Property="Label.TextColor"
Value="Transparent" />
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Invalid">
<VisualState.Setters>
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Pink" />
<Setter TargetName="submitButton"
Property="Button.IsEnabled"
Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="Enter a U.S. phone number:"
FontSize="18" />
<Entry x:Name="entry"
Placeholder="555-555-5555"
FontSize="18"
Margin="30, 0, 0, 0"
TextChanged="OnTextChanged" />
<Label x:Name="helpLabel"
Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1" />
<Button x:Name="submitButton"
Text="Submit"
FontSize="18"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
Neste exemplo, os estados visuais são anexados ao StackLayout e há dois estados mutuamente exclusivos chamados Valid
e Invalid
. Se o Entry não contiver um número de telefone válido, o estado atual será Invalid
e, portanto, o Entry terá um plano de fundo rosa, o segundo Label ficará visível e o Button será desabilitado. Quando um número de telefone válido é inserido, o estado atual se torna Valid
. O Entry recebe um fundo limão, o segundo Label desaparece e o Button agora está habilitado:
O arquivo code-behind é responsável por manipular o evento TextChanged
do Entry. O manipulador usa uma expressão regular para determinar se a cadeia de caracteres de entrada é válida ou não. O método GoToState
no arquivo code-behind chama o método VisualStateManager.GoToState
estático no objeto StackLayout:
public partial class VsmValidationPage : ContentPage
{
public VsmValidationPage()
{
InitializeComponent();
GoToState(false);
}
void OnTextChanged(object sender, TextChangedEventArgs args)
{
bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
GoToState(isValid);
}
void GoToState(bool isValid)
{
string visualState = isValid ? "Valid" : "Invalid";
VisualStateManager.GoToState(stackLayout, visualState);
}
}
Neste exemplo, o método GoToState
é chamado do construtor para inicializar o estado. Deve haver sempre um estado atual. O arquivo code-behind chama VisualStateManager.GoToState
, com um nome de estado, no objeto que define os estados visuais.
Gatilhos de estado visual
Os estados visuais oferecem suporte a gatilhos de estado, que são um grupo especializado de gatilhos que definem as condições sob as quais um VisualState deve ser aplicado.
Os gatilhos de estado são adicionados à coleção de StateTriggers de um VisualState. Essa coleção pode conter um ou vários gatilhos de estado. Um VisualState será aplicado quando qualquer gatilho de estado na coleção estiver ativo.
Ao usar gatilhos de estado para controlar estados visuais, o .NET MAUI usa as seguintes regras de precedência para determinar qual gatilho (e VisualStatecorrespondente) estará ativo:
- Um gatilho que deriva de StateTriggerBase.
- Um AdaptiveTrigger ativado porque a condição MinWindowWidth foi atendida.
- Um AdaptiveTrigger ativado porque a condição MinWindowHeight foi atendida.
Se múltiplos gatinhos estiverem simultaneamente ativos (por exemplo, dois gatilhos personalizados), o primeiro gatilho declarado na marcação terá precedência.
Para obter mais informações sobre gatilhos de estado, consulte Gatilhos de estado.