Tutorial Windows Phone: Animando componentes visuais no Windows Phone
Introdução
Neste tutorial ensinaremos a como animar componentes visuais no Windows Phone. Componentes nativos do sistema Windows Phone já possuem por padrão animações que respondem a vários comportamentos, porém componentes definidos pelo usuário, user control, não apresentam comportamento visual condizentes com a plataforma. Para corrigir isso devemos definir os estados visuais do componente e como alterar entre eles de acordo com a iteração do usuário.
Usando o Blend
Para definir os estados e ações necessárias para animar um componente utilizaremos o Blend, ferramenta disponibilizada junto com o Visual Studio que possui foco na criação das telas e componentes visuais do aplicativo. Esse tutorial usará o componente criado em um tutorial anterior como base.
Você pode abrir o Blend direto através do Windows ou pode abrir ele pelo próprio Visual Studio. A vantagem de abrir direto por dentro do Visual Studio é que ele já inicia no projeto que você está trabalhando. Para abrir através do Visual Studio selecione o menu Project, seguido pela opção Open in Blend.
Definindo estados visuais
Um estado visual corresponde ao estado do componente sobre determinadas situações, alguns exemplos de estados usuais incluem: normal, pressionado, selecionado, desativado, etc. Neste exemplo criaremos somente dois estados, normal, pressionado. A diferença deles será somente a cor de fundo do botão, cinza claro no estado normal e cinza escuro quando pressionado.
Para criar um estado visual clique na aba States do Blend. Clique em Add State, dê o nome de Normal e não faça mais alterações neste estado. Este estado será o estado normal do componente, para criar o estado que representa o botão pressionado repita o processo, dando o nome de Pressionado para o novo estado. Quando você selecionar um dos estados note que a área de trabalho fica rodeada por uma margem vermelha e uma mensagem indicando que as alterações estão sendo gravadas. Isso ai indica que qualquer alteração feita será persistida no estado que está selecionado.
Para modificar o estado Pressionado selecione o mesmo, e clique no item que representa o layout do componente, no caso ImageButtonLayoutRoot, em seguida altere o valor do Backgroud para a cor desejada.
Com os estados definidos devemos definir como o componente altera entre os mesmos.
Definindo transições entre estados
Para criar uma transição do estado Pressionado para o estado Normal selecione o estado Pressionado, clique no botão Add Transition, representado por uma seta com um simbolo de mais, selecione a opção Pressionado -> Normal. Um bom valor para a transição é 0.5 segundos, o Easing Function é um método fácil de definir o comportamento de mudança através do tempo. Podemos deixar a opção de progressão linear que é definida por Default. Uma transição de Normal para Pressionado deve ter um valor de transição bem baixo, pois valores maiores dão a impressão de demora de resposta do programa.
Definindo comportamento
Para alternar entre os estados devemos criar duas ações de comportamento sendo uma para alternar para o estado Pressionado e outra para alternar para o estado Normal. Para adicionar essas ações, clique na aba Assets e selecione a opção Behavior. Arraste o item GoToStateAction para o ImageButtonLayoutRoot.
Nomeie a ação de forma a indicar que ela altera para o estado Pressionado. Embora estejamos desenvolvendo para o Windows Phone usaremos o evento Mouse Enter para tratar quando o item é selecionado, para tratar esta transição outros eventos podem funcionar de forma semelhante, tal como o evento Tap. Além de definir qual o evento que chama essa ação devemos definir qual é o estado que essa ação chama, para isso selecione o estado Pressionado definido anteriormente.
A ação que volta o componente para o estado normal é definido de forma semelhante, porém deve-se selecionar o evento MouseLeave para tratar quando o botão é solto e o estado Normal como destino.
Conclusão
O código que implementa o componente com os estados visuais e suas transições pode ser visto abaixo.
[sourcecode language=”xml” wraplines=”false” collapse=”true”]
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:ec="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" xmlns:eim="clr-namespace:Microsoft.Expression.Interactivity.Media;assembly=Microsoft.Expression.Interactions" xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Input;assembly=Microsoft.Expression.Interactions" x:Name="userControl" x:Class="UGuideUFOP.Utils.ImageButton"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="240" d:DesignWidth="200">
<Grid x:Name="ImageButtonLayoutRoot" Background="#FFB9B9B9" RenderTransformOrigin="0.5,0.5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ec:GoToStateAction x:Name="ToPressed" StateName="Pressed"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ec:GoToStateAction x:Name="ToNormal" StateName="Normal"/>
</i:EventTrigger>
<ec:DataTrigger Binding="{Binding IsEnabled, ElementName=userControl}" Value="True">
<ec:GoToStateAction x:Name="ToDisabled" StateName="Disabled"/>
</ec:DataTrigger>
</i:Interaction.Triggers>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Pressed" GeneratedDuration="0:0:0.5" To="Normal"/>
<VisualTransition GeneratedDuration="0:0:1" To="Normal"/>
<VisualTransition GeneratedDuration="0:0:0.5" To="Disabled">
<VisualTransition.GeneratedEasingFunction>
<CubicEase EasingMode="EaseIn"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimation Duration="0" To="#FFC9C9C9" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="ImageButtonLayoutRoot" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0" To="#FF828282" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="ImageButtonLayoutRoot" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ColorAnimation Duration="0" To="#FFC34444" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="ImageButtonLayoutRoot" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Image x:Name="Image" Width="auto" Grid.Row="0" Margin="10,10,10,10"/>
<TextBlock x:Name="Label" TextAlignment="Center" Grid.Row="1" Foreground="White" FontSize="24" Margin="10,10,10,10"/>
</Grid>
</UserControl>
[/sourcecode]
Este tutorial mostra um exemplo simples de animação de componentes no Windows Phone tratando o clique e soltura de um botão. Utilizando outras ações e comportamentos é possível definir animações que exibem mensagens, contadores e outros de forma visualmente agradável.