Visão geral das transformações

Saiba como usar transformações na API do Windows Runtime alterando os sistemas de coordenadas relativas de elementos na interface do usuário. Isso pode ser usado para ajustar a aparência de elementos XAML individuais, como dimensionamento, rotação ou transformação da posição em espaço x-y.

O que é uma transformação?

Uma transformação define como mapear ou transformar pontos de um espaço de coordenadas para outro espaço de coordenadas. Quando uma transformação é aplicada a um elemento de interface do usuário, ela altera como esse elemento de interface do usuário é renderizado na tela como parte da interface do usuário.

Pense em transformações em quatro classificações amplas: translação, rotação, escala e distorção (ou cisalhamento). Para usar APIs gráficas para alterar a aparência dos elementos da interface do usuário, geralmente é mais fácil criar transformações que definem apenas uma operação por vez. Portanto, o Windows Runtime define uma classe discreta para cada uma dessas classificações de transformação:

Destes, é provável que você use TranslateTransform e ScaleTransform com mais frequência para cenários de interface do usuário.

Você pode combinar transformações e há duas classes do Windows Runtime que dão suporte a isso: CompositeTransform e TransformGroup. Em um CompositeTransform, as transformações são aplicadas nesta ordem: dimensionar, distorcer, girar, traduzir. Use TransformGroup em vez de CompositeTransform se desejar que as transformações se apliquem em uma ordem diferente. Para obter mais informações, consulte CompositeTransform.

Transformações e layout

No layout XAML, as transformações são aplicadas após a conclusão da passagem de layout, portanto, cálculos de espaço disponíveis e outras decisões de layout foram tomadas antes que as transformações sejam aplicadas. Como o layout vem primeiro, às vezes você obterá resultados inesperados se modificar elementos que estão em uma célula Grid ou em um contêiner de layout semelhante que aloca espaço no momento do layout. O elemento transformado pode parecer truncado ou obscurecido porque está tentando desenhar em uma área que não calculou as dimensões pós-transformação ao dividir espaço dentro de seu contêiner pai. Talvez seja necessário experimentar os resultados da transformação e ajustar algumas configurações. Por exemplo, em vez de depender do layout adaptável e do dimensionamento de estrelas, talvez seja necessário alterar as propriedades do Center ou declarar medidas de pixel fixas para o espaço de layout para garantir que o pai aloca espaço suficiente.

Observação de migração: Windows Presentation Foundation (WPF) tinha uma propriedade LayoutTransform que aplicava transformações antes da passagem de layout. Mas o XAML do Windows Runtime não dá suporte a uma propriedade LayoutTransform . (O Microsoft Silverlight também não tinha essa propriedade.)

Dica

Como alternativa, o Kit de Ferramentas da Comunidade do Windows fornece o LayoutTransformControl, que aplica transformações de matriz em qualquer FrameworkElement (elemento da estrutura) do seu aplicativo.

Aplicando uma transformação a um elemento de interface do usuário

Quando você aplica uma transformação a um objeto, normalmente faz isso para definir a propriedade UIElement.RenderTransform. Definir essa propriedade não altera literalmente o objeto pixel por pixel. O que a propriedade realmente faz é aplicar a transformação dentro do espaço de coordenada local no qual esse objeto existe. Em seguida, a lógica de renderização e a operação (post-layout) renderizam os espaços de coordenadas combinados, fazendo com que pareça que o objeto mudou de aparência e também potencialmente de posição de layout (caso TranslateTransform tenha sido aplicado).

Por padrão, cada transformação de render é centralizada na origem do sistema de coordenadas local do objeto de destino, o ponto (0,0). A única exceção é um TranslateTransform, que não tem propriedades de centro a serem definidas porque o efeito de tradução é o mesmo, independentemente de onde está centralizado. Mas as outras transformações têm propriedades que definem valores de CenterX e CenterY.

Sempre que você usar transformações com UIElement.RenderTransform, lembre-se de que há outra propriedade em UIElement que afeta o comportamento da transformação: RenderTransformOrigin. O que RenderTransformOrigin declara é se toda a transformação deve ser aplicada ao ponto padrão (0,0) de um elemento ou a algum outro ponto de origem dentro do espaço de coordenada relativa desse elemento. Para elementos típicos, (0,0) coloca a transformação no canto superior esquerdo. Dependendo do efeito desejado, você pode optar por alterar RenderTransformOrigin em vez de ajustar os valores de CenterX e CenterY nas transformações. Observe que, se você aplicar ambos os valores RenderTransformOrigin e CenterX / CenterY, os resultados poderão ser bastante confusos, especialmente se você estiver animando qualquer um dos valores.

Para fins de teste de ocorrência, um objeto ao qual uma transformação é aplicada continua respondendo à entrada de uma maneira esperada que seja consistente com sua aparência visual no espaço x-y. Por exemplo, se você usou um TranslateTransform para mover um retângulo lateralmente 400 pixels na interface do usuário, esse retângulo responderá a eventos de PointerPressed quando o usuário pressiona o local onde o retângulo aparece visualmente. Você não obterá eventos falsos se o usuário pressionar a área onde o Rectangle estava antes de ser traduzido. Para quaisquer considerações de índice z que afetam o teste de ocorrência, a aplicação de uma transformação não faz diferença; o índice z que controla qual elemento manipula eventos de entrada para um ponto no espaço x-y ainda é avaliado usando a ordem filho, conforme declarado em um contêiner. Essa ordem geralmente é a mesma que a ordem na qual você declara os elementos em XAML, embora para elementos filhos de um objeto Canvas você possa ajustar a ordem aplicando a propriedade associada Canvas.ZIndex a elementos filhos.

Outras propriedades de transformação

  • Brush.Transform, Brush.RelativeTransform: elas influenciam como um Brush usa espaço de coordenadas dentro da área em que o Brush é aplicado para definir propriedades visuais, como planos de fundo e primeiro plano. Essas transformações não são relevantes para os pincéis mais comuns (que normalmente estão definindo cores sólidas com SolidColorBrush), mas podem ser ocasionalmente úteis ao pintar áreas com um ImageBrush ou LinearGradientBrush.
  • Geometry.Transform: você pode usar essa propriedade para aplicar uma transformação a uma geometria antes de usar essa geometria como valor da propriedade Path.Data.

animando uma transformação

Transformar objetos podem ser animados. Para animar um Transform, aplique uma animação de um tipo compatível à propriedade que você deseja animar. Isso normalmente significa que você está usando objetos DoubleAnimation ou DoubleAnimationUsingKeyFrames para definir a animação, pois todas as propriedades de transformação são do tipo Double. Animações que afetam uma transformação usada para um valor UIElement.RenderTransform não são consideradas animações dependentes, mesmo que tenham uma duração diferente de zero. Para obter mais informações sobre animações dependentes, consulte animações de storyboard.

Se você animar propriedades para produzir um efeito semelhante a uma transformação em termos de aparência visual geral — por exemplo, animando o Width e Height de um FrameworkElement em vez de aplicar um TranslateTransform— essas animações são quase sempre tratadas como animações dependentes. Você teria que habilitar as animações e poderia haver problemas significativos de desempenho com a animação, especialmente se você estiver tentando dar suporte à interação do usuário enquanto esse objeto está sendo animado. Por esse motivo, é preferível usar uma transformação e animá-la em vez de animar qualquer outra propriedade em que a animação seja tratada como uma animação dependente.

Para aplicar a transformação, deve existir um Transform como valor para RenderTransform. Normalmente, você coloca um elemento para o tipo de transformação apropriado no XAML inicial, às vezes sem propriedades definidas nessa transformação.

Normalmente, você usa uma técnica de direcionamento indireto para aplicar animações às propriedades de uma transformação. Para obter mais informações sobre a sintaxe de direcionamento indireto, consulte animações com storyboard e sintaxe de caminho de propriedade.

Os estilos padrão para controles às vezes definem animações de transformações como parte de seu comportamento de estado visual. Por exemplo, os estados visuais para ProgressRing usam valores animados RotateTransform para "girar" os pontos no anel.

Aqui está um exemplo simples de como animar uma transformação. Nesse caso, ele está animando o Angle de um RotateTransform para girar um retângulo no lugar em torno de seu centro visual. Este exemplo nomeia o RotateTransform , portanto, não precisa de direcionamento indireto de animação, mas você pode, como alternativa, deixar a transformação sem nome, nomear o elemento ao qual a transformação é aplicada e usar o direcionamento indireto, como (UIElement.RenderTransform).(RotateTransform.Angle).

<StackPanel Margin="15">
  <StackPanel.Resources>
    <Storyboard x:Name="myStoryboard">
      <DoubleAnimation
       Storyboard.TargetName="myTransform"
       Storyboard.TargetProperty="Angle"
       From="0" To="360" Duration="0:0:5" 
       RepeatBehavior="Forever" />
    </Storyboard>
  </StackPanel.Resources>
  <Rectangle Width="50" Height="50" Fill="RoyalBlue"
   PointerPressed="StartAnimation">
    <Rectangle.RenderTransform>
      <RotateTransform x:Name="myTransform" Angle="45" CenterX="25" CenterY="25" />
    </Rectangle.RenderTransform>
  </Rectangle>
</StackPanel>
void StartAnimation (object sender, RoutedEventArgs e) {
    myStoryboard.Begin();
}

Gestão de quadros de coordenação de referência em tempo de execução

UIElement tem um método chamado TransformToVisual, que pode gerar um Transform que correlaciona os quadros de referência de coordenadas para dois elementos da interface do usuário. Você pode usar isto para comparar um elemento ao quadro de referência padrão de coordenadas do aplicativo se você passar o elemento visual raiz como o primeiro parâmetro. Isso pode ser útil se você capturou um evento de entrada de um elemento diferente ou se estiver tentando prever o comportamento do layout sem realmente solicitar uma passagem de layout.

Observação

(UWP) Os dados de evento obtidos de eventos de ponteiro fornecem acesso a um método GetCurrentPoint , em que você pode especificar um parâmetro relativeTo para alterar o quadro de referência de coordenada para um elemento específico em vez do padrão do aplicativo. Essa abordagem simplesmente aplica uma transformação de tradução internamente e transforma os dados de coordenada x-y para você quando cria o objeto PointerPoint retornado.

Descrevendo uma transformação matematicamente

Uma transformação pode ser descrita em termos de matriz de transformação. Uma matriz 3×3 é usada para descrever as transformações em um plano x-y bidimensional. Matrizes de transformação afim podem ser multiplicadas para formar qualquer número de transformações lineares, como rotação e cisalhamento, seguidas de translação. A coluna final de uma matriz de transformação affine é igual a (0, 0, 1), portanto, você precisa especificar apenas os membros das duas primeiras colunas na descrição matemática.

A descrição matemática de uma transformação pode ser útil para você se você tiver uma experiência matemática ou familiaridade com técnicas de programação gráfica que também usam matrizes para descrever transformações de espaço de coordenadas. Há uma classe derivada Transformque permite expressar uma transformação diretamente em termos de sua matriz 3×3: MatrixTransform. MatrixTransform tem uma propriedade Matrix , que contém uma estrutura que tem seis propriedades: M11, M12, M21, M22, OffsetX e OffsetY. Cada propriedade Matrix usa um valor Double e corresponde aos seis valores relevantes (colunas 1 e 2) de uma matriz de transformação afim.

Coluna 1 Coluna 2 Coluna 3
M11 M12 0
M21 M22 0
OffsetX DeslocamentoY 1

Qualquer transformação que você possa descrever com umTranslateTransform, ScaleTransform, RotateTransform ou SkewTransform pode ser descrita igualmente por um MatrixTransform com um valor de Matriz . Mas você normalmente só usa TranslateTransform e os outros porque as propriedades nessas classes de transformação são mais fáceis de conceituar do que definir os componentes de vetor em uma Matriz. Também é mais fácil animar as propriedades discretas das transformações; uma Matriz é, na verdade, uma estrutura e não um DependencyObject, portanto, não pode dar suporte a valores individuais animados.

Algumas ferramentas de design XAML que permitem aplicar operações de transformação serializarão os resultados como um MatrixTransform. Nesse caso, talvez seja melhor usar a mesma ferramenta de design novamente para alterar o efeito de transformação e serializar o XAML novamente, em vez de tentar manipular os valores de Matriz diretamente no XAML.

transformações 3D

No Windows 10, o XAML introduziu uma nova propriedade, UIElement.Transform3D, que pode ser usada para criar efeitos 3D com a interface do usuário. Para fazer isso, use PerspectiveTransform3D para adicionar uma perspectiva 3D compartilhada ou "câmera" à sua cena e, em seguida, use CompositeTransform3D para transformar um elemento no espaço 3D, como você usaria CompositeTransform. Consulte UIElement.Transform3D para obter uma discussão sobre como implementar transformações 3D.

Para efeitos 3D mais simples que se aplicam apenas a um único objeto, a propriedade UIElement.Projection pode ser usada. Usar um PlaneProjection como o valor dessa propriedade equivale a aplicar uma transformação de perspectiva fixa e uma ou mais transformações tridimensionais ao elemento. Esse tipo de transformação é descrito com mais detalhes em efeitos de perspectiva 3D para interface do usuário XAML.