Xamarin.Forms Gerenciador de Estado Visual
Use o Gerenciador de Estado Visual para fazer alterações em elementos XAML com base em estados visuais definidos a partir do código.
O VSM (Visual State Manager) 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 do aplicativo é definida em XAML, e esse XAML inclui marcação que descreve como o Visual State Manager afeta os visuais da interface do usuário.
O VSM introduz o conceito de estados visuais. Uma Xamarin.Forms exibição como a Button
pode ter várias aparências visuais diferentes, dependendo de seu estado subjacente — se está desabilitada, pressionada 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 Xamarin.Forms Visual State Manager define um grupo de estados visuais chamado "CommonStates" com os seguintes estados visuais:
- "Normal"
- "Desativado"
- "Focado"
- "Selecionado"
Esse grupo de estados visuais tem suporte para todas as classes derivadas de VisualElement
, que é a classe base para View
e Page
.
Você também pode definir seus próprios grupos de estados visuais e estados visuais, como este artigo demonstrará.
Observação
Xamarin.Forms Os desenvolvedores familiarizados com gatilhos estão cientes de que os gatilhos também podem fazer alterações nos visuais na interface do usuário com base nas alterações nas propriedades de uma exibição ou no disparo de eventos. No entanto, usar gatilhos para lidar com várias combinações dessas alterações pode se tornar bastante confuso. Historicamente, o Visual State Manager foi introduzido em ambientes baseados em XAML do Windows para aliviar a confusão resultante de combinações de estados visuais. Com o VSM, os estados visuais dentro de um grupo de estados visuais são sempre mutuamente exclusivos. A qualquer momento, apenas um estado em cada grupo é o estado atual.
Estados comuns
O Gerenciador de Estado Visual permite que você inclua marcação em seu arquivo XAML que pode alterar a aparência visual de um modo de exibição se o modo de exibição for normal, desabilitado ou tiver o foco de entrada. 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 oEntry
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.
Você pode anexar a marcação VSM a uma exibição individual ou pode defini-la em um estilo se ela se aplicar a várias exibições. As próximas duas seções descrevem essas abordagens.
Marcação VSM em uma exibição
Para anexar a marcação VSM a uma Entry
exibição, primeiro separe as Entry
tags inicial e final:
<Entry FontSize="18">
</Entry>
Ele recebe um tamanho de fonte explícito porque um dos estados usará a FontSize
propriedade para dobrar o tamanho do texto no Entry
.
Em seguida, insira VisualStateManager.VisualStateGroups
tags entre essas tags:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualStateGroups
é uma propriedade associável anexada VisualStateManager
definida pela classe. (Para obter mais informações sobre propriedades vinculáveis anexadas, consulte o artigo Propriedades anexadas.) É assim que a VisualStateGroups
propriedade é anexada Entry
ao objeto.
A propriedade VisualStateGroups
é do tipo VisualStateGroupList
, que é uma coleção de objetos VisualStateGroup
. Dentro das VisualStateManager.VisualStateGroups
tags, insira um par de VisualStateGroup
tags para cada grupo de estados visuais que você deseja incluir:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Observe que a VisualStateGroup
tag tem um x:Name
atributo indicando o nome do grupo. A VisualStateGroup
classe define uma Name
propriedade que você pode usar:
<VisualStateGroup Name="CommonStates">
Você pode usar um x:Name
ou Name
mas não ambos no mesmo elemento.
A classe VisualStateGroup
define uma propriedade chamada States
, que é uma coleção de objetos VisualState
. States
é a propriedade content de VisualStateGroups
para que você possa incluir as VisualState
tags diretamente entre as VisualStateGroup
tags. (As propriedades de conteúdo são discutidas no artigo Sintaxe XAML essencial.)
A próxima etapa é incluir um par de tags para cada estado visual nesse grupo. Estes também podem ser identificados usando x:Name
ou Name
:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
</VisualState>
<VisualState x:Name="Focused">
</VisualState>
<VisualState x:Name="Disabled">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualState
define uma propriedade chamada Setters
, que é uma coleção de Setter
objetos. Esses são os mesmos objetos Setter
que você usa em um objeto Style
.
Setters
não é a propriedade content de , portanto, é necessário incluir tags de VisualState
elemento de propriedade para a Setters
propriedade:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Agora você pode inserir um ou mais Setter
objetos entre cada par de Setters
tags. Estes são os Setter
objetos que definem os estados visuais descritos anteriormente:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Cada Setter
tag indica o valor de uma propriedade específica quando esse estado é atual. Qualquer propriedade com referência a um objeto Setter
deve ser apoiada por uma propriedade vinculável.
Marcação semelhante a essa é a base da página VSM na exibição no programa de exemplo. A página inclui três Entry
visualizações, mas apenas a segunda tem a marcação VSM anexada a ela:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VsmDemos"
x:Class="VsmDemos.MainPage"
Title="VSM Demos">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Label Text="Normal Entry:" />
<Entry />
<Label Text="Entry with VSM: " />
<Entry>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Label Text="Entry to enable 2nd Entry:" />
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Observe que o segundo Entry
também tem um DataTrigger
como parte de sua Trigger
coleção. Isso faz com que o seja Entry
desativado até que algo seja digitado no terceiro Entry
. Aqui está a página na inicialização em execução no iOS, Android e na Plataforma Universal do Windows (UWP):
O estado visual atual é "Desativado", portanto, o plano de fundo do segundo Entry
é rosa nas telas do iOS e do Android. A implementação UWP de não permite definir a cor da tela de Entry
fundo quando o Entry
está desabilitado.
Quando você insere algum texto no terceiro Entry
, o segundo Entry
muda para o estado "Normal" e o plano de fundo agora é limão:
Quando você toca no segundo Entry
, ele obtém o foco de entrada. Ele muda para o estado "Focado" e se expande para o dobro de sua altura:
Observe que o Entry
não retém o fundo de cal quando obtém o foco de entrada. Como o Gerenciador de Estado Visual alterna entre os estados visuais, as definições das propriedades definidas pelo estado anterior são removidas. Lembre-se de que os estados visuais são mutuamente exclusivos. O estado "Normal" não significa apenas que o Entry
está habilitado. Isso significa que o Entry
está habilitado e não tem foco de entrada.
Se você quiser que o Entry
tenha um plano de fundo limão no estado "Focado", adicione outro Setter
a esse estado visual:
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
Para que esses Setter
objetos funcionem corretamente, a VisualStateGroup
deve conter VisualState
objetos para todos os estados desse grupo. Se houver um estado visual que não tenha nenhum Setter
objeto, inclua-o de qualquer maneira como uma tag vazia:
<VisualState x:Name="Normal" />
Marcação do Visual State Manager em um estilo
Geralmente, é necessário compartilhar a mesma marcação do Visual State Manager entre duas ou mais exibições. Nesse caso, você desejará colocar a marcação em uma Style
definição.
Aqui está o implícito Style
existente para os Entry
elementos na página VSM On View :
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
Adicione Setter
tags para a VisualStateManager.VisualStateGroups
propriedade associável anexada:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
</Setter>
</Style>
A propriedade de conteúdo para Setter
é Value
, portanto, o valor da Value
propriedade pode ser especificado diretamente nessas tags. Essa propriedade é do tipo VisualStateGroupList
:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
</VisualStateGroupList>
</Setter>
</Style>
Dentro dessas tags, você pode incluir um ou mais VisualStateGroup
objetos:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
O restante da marcação VSM é o mesmo de antes.
Aqui está a página VSM em estilo mostrando a marcação VSM completa:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmInStylePage"
Title="VSM in Style">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Label Text="Normal Entry:" />
<Entry />
<Label Text="Entry with VSM: " />
<Entry>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Label Text="Entry to enable 2nd Entry:" />
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Agora, todas as Entry
visualizações nesta página respondem da mesma maneira aos seus estados visuais. Observe também que o estado "Focado" agora inclui um segundo Setter
que dá a cada Entry
um um fundo limão também quando tem foco de entrada:
Estados visuais em Xamarin.Forms
A tabela a seguir lista os estados visuais definidos em Xamarin.Forms:
Classe | Estados | Mais informações |
---|---|---|
Button |
Pressed |
Estados visuais Button |
CheckBox |
IsChecked |
Estados visuais CheckBox |
CarouselView |
DefaultItem , CurrentItem , PreviousItem , NextItem |
Estados visuais CarouselView |
ImageButton |
Pressed |
Estados visuais ImageButton |
RadioButton |
Checked , Unchecked |
Estados visuais RadioButton |
Switch |
On , Off |
Estados visuais Switch |
VisualElement |
Normal , Disabled , Focused , Selected |
Estados comuns |
Cada um desses estados pode ser acessado por meio do grupo de estados visuais chamado CommonStates
.
Além disso, o implementa CollectionView
o Selected
estado. Para obter mais informações, consulte Alterar a cor do item selecionado.
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 Setter
tipo tem uma TargetName
propriedade, do tipo string
, que representa o elemento de destino que o Setter
para um estado visual manipulará. Quando a TargetName
propriedade é definida, o Setter
define o Property
elemento 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.
A página VSM com Setter TargetName no exemplo mostra como definir o estado em vários elementos, a partir de um único grupo de estados visuais. O arquivo XAML consiste em um StackLayout
elemento que contém Label
, um Entry
e um Button
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmSetterTargetNamePage"
Title="VSM with Setter TargetName">
<StackLayout Margin="10">
<Label Text="What is the capital of France?" />
<Entry x:Name="entry"
Placeholder="Enter answer" />
<Button Text="Reveal answer">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x: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>
</ContentPage>
A marcação VSM é anexada StackLayout
ao . Há dois estados mutuamente exclusivos, chamados "Normal" e "Pressionado", com cada estado contendo VisualState
tags.
O estado "Normal" está ativo quando o Button
não é pressionado e uma resposta à pergunta pode ser inserida:
O estado "Pressionado" torna-se ativo quando o Button
é pressionado:
O "Pressionado" VisualState
especifica que, quando o Button
é pressionado, sua Scale
propriedade 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 o 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
No momento, não há suporte para caminhos de propriedade em Setter
elementos que especificam a TargetName
propriedade.
Defina seus próprios estados visuais
Cada classe derivada de VisualElement
suporta os estados comuns "Normal", "Focado" e "Desabilitado". Além disso, a CollectionView
classe dá suporte ao estado "Selected". Internamente, a classe detecta VisualElement
quando está sendo habilitada ou desabilitada, ou focada ou desfocada, e chama o método estático VisualStateManager.GoToState
:
VisualStateManager.GoToState(this, "Focused");
Esse é o único código do Visual State Manager que você encontrará na VisualElement
classe. Como GoToState
é chamado para cada objeto com base em cada classe derivada de VisualElement
, você pode usar o Visual State Manager com qualquer VisualElement
objeto para responder a essas alterações.
Curiosamente, o nome do grupo de estados visuais "CommonStates" não é explicitamente referenciado no VisualElement
. O nome do grupo não faz parte da API do Visual State Manager. Em um dos dois programas de amostra mostrados até agora, você pode alterar o nome do grupo de "CommonStates" para qualquer outra coisa, e o programa ainda funcionará. O nome do grupo é apenas uma descrição geral dos estados desse grupo. Entende-se implicitamente que os estados visuais em qualquer grupo são mutuamente exclusivos: um estado e apenas um estado são atuais a qualquer momento.
Se você quiser implementar seus próprios estados visuais, precisará chamar VisualStateManager.GoToState
do código. Na maioria das vezes, você fará essa chamada do arquivo code-behind da sua classe de página.
A página Validação do VSM no exemplo mostra como usar o Visual State Manager em conexão com a validação de entrada. O arquivo XAML consiste em um StackLayout
contendo dois Label
elementos, um Entry
, e um Button
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
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="Large" />
<Entry x:Name="entry"
Placeholder="555-555-5555"
FontSize="Large"
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="Large"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
A marcação VSM é anexada StackLayout
ao (nomeado stackLayout
). Há dois estados mutuamente exclusivos, chamados "Válido" e "Inválido", com cada estado contendo VisualState
marcas.
Se o Entry
não contiver um número de telefone válido, o estado atual será "Inválido" e, portanto, o Entry
terá um fundo rosa, o segundo Label
ficará visível e o Button
será desativado:
Quando um número de telefone válido é inserido, o estado atual se torna "Válido". 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 no arquivo code-behind chamado GoToState
chama o método estático VisualStateManager.GoToState
para 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);
}
}
Observe também que o GoToState
método é chamado do construtor para inicializar o estado. Deve haver sempre um estado atual. Mas em nenhum lugar do código há qualquer referência ao nome do grupo de estados visuais, embora ele seja referenciado no XAML como "ValidationStates" para fins de clareza.
Observe que o arquivo code-behind só precisa levar em conta o objeto na página que define os estados visuais e chamar VisualStateManager.GoToState
esse objeto. Isso ocorre porque ambos os estados visuais são direcionados a vários objetos na página.
Você pode se perguntar: se o arquivo code-behind deve fazer referência ao objeto na página que define os estados visuais, por que o arquivo code-behind não pode simplesmente acessar esse e outros objetos diretamente? Certamente poderia. No entanto, a vantagem de usar o VSM é que você pode controlar como os elementos visuais reagem a diferentes estados inteiramente em XAML, o que mantém todo o design da interface do usuário em um único local. Isso evita definir a aparência visual acessando elementos visuais diretamente do code-behind.
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, Xamarin.Forms usa as seguintes regras de precedência para determinar qual gatilho (e correspondente VisualState
) estará ativo:
- Um gatilho que deriva de
StateTriggerBase
. - Um
AdaptiveTrigger
ativado porque a condiçãoMinWindowWidth
foi atendida. - Um
AdaptiveTrigger
ativado porque a condiçãoMinWindowHeight
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.
Usar o Visual State Manager para layout adaptável
Um Xamarin.Forms aplicativo em execução em um telefone geralmente pode ser visualizado em uma proporção retrato ou paisagem, e um Xamarin.Forms programa em execução na área de trabalho pode ser redimensionado para assumir muitos tamanhos e proporções diferentes. Um aplicativo bem projetado pode exibir seu conteúdo de forma diferente para esses vários fatores forma de página ou janela.
Essa técnica às vezes é conhecida como layout adaptável. Como o layout adaptável envolve apenas os visuais de um programa, ele é uma aplicação ideal do Visual State Manager.
Um exemplo simples é um aplicativo que exibe uma pequena coleção de botões que afetam o conteúdo do aplicativo. No modo retrato, esses botões podem ser exibidos em uma linha horizontal na parte superior da página:
No modo paisagem, a matriz de botões pode ser movida para um lado e exibida em uma coluna:
De cima para baixo, o programa está sendo executado na Plataforma Universal do Windows, Android e iOS.
A página Layout Adaptável do VSM no exemplo define um grupo chamado "OrientationStates" com dois estados visuais chamados "Retrato" e "Paisagem". (Uma abordagem mais complexa pode ser baseada em várias larguras de página ou janela diferentes.)
A marcação VSM ocorre em quatro locais no arquivo XAML. O StackLayout
nomeado mainStack
contém o menu e o conteúdo, que é um Image
elemento. Isso StackLayout
deve ter uma orientação vertical no modo retrato e uma orientação horizontal no modo paisagem:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmAdaptiveLayoutPage"
Title="VSM Adaptive Layout">
<StackLayout x:Name="mainStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollView x:Name="menuScroll">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout x:Name="menuStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout.Resources>
<Style TargetType="Button">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
<Setter Property="Margin" Value="10, 5" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="Margin" Value="10" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</StackLayout.Resources>
<Button Text="Banana"
Command="{Binding SelectedCommand}"
CommandParameter="Banana.jpg" />
<Button Text="Face Palm"
Command="{Binding SelectedCommand}"
CommandParameter="FacePalm.jpg" />
<Button Text="Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="monkey.png" />
<Button Text="Seated Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="SeatedMonkey.jpg" />
</StackLayout>
</ScrollView>
<Image x:Name="image"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
O nome menuScroll
interno ScrollView
e o StackLayout
nomeado menuStack
implementam o menu de botões. A orientação desses layouts é oposta a mainStack
. O menu deve ser horizontal no modo retrato e vertical no modo paisagem.
A quarta seção da marcação VSM está em um estilo implícito para os próprios botões. Essa marcação define VerticalOptions
, HorizontalOptions
e Margin
propriedades específicas para as orientações retrato e paisagem.
O arquivo code-behind define a propriedade de menuStack
para implementar Button
o BindingContext
comando e também anexa um manipulador ao SizeChanged
evento da página:
public partial class VsmAdaptiveLayoutPage : ContentPage
{
public VsmAdaptiveLayoutPage ()
{
InitializeComponent ();
SizeChanged += (sender, args) =>
{
string visualState = Width > Height ? "Landscape" : "Portrait";
VisualStateManager.GoToState(mainStack, visualState);
VisualStateManager.GoToState(menuScroll, visualState);
VisualStateManager.GoToState(menuStack, visualState);
foreach (View child in menuStack.Children)
{
VisualStateManager.GoToState(child, visualState);
}
};
SelectedCommand = new Command<string>((filename) =>
{
image.Source = ImageSource.FromResource("VsmDemos.Images." + filename);
});
menuStack.BindingContext = this;
}
public ICommand SelectedCommand { private set; get; }
}
O SizeChanged
manipulador chama VisualStateManager.GoToState
os elementos two StackLayout
and ScrollView
e, em seguida, percorre os filhos de menuStack
para chamar VisualStateManager.GoToState
os Button
elementos.
Pode parecer que o arquivo code-behind pode lidar com alterações de orientação mais diretamente definindo propriedades de elementos no arquivo XAML, mas o Visual State Manager é definitivamente uma abordagem mais estruturada. Todos os visuais são mantidos no arquivo XAML, onde se tornam mais fáceis de examinar, manter e modificar.
Gerenciador de Estado Visual com Xamarin.University
Xamarin.Forms 3.0 Vídeo do Visual State Manager