Compartilhar via


Visão geral das transformações

Saiba como usar transformações na API do Tempo de Execução do Windows, alterando os sistemas de coordenadas relativos dos elementos na interface do usuário. Isso pode ser usado para ajustar a aparência de elementos XAML individuais, como dimensionar, girar ou transformar a posição no 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 a forma como esse elemento de interface do usuário é renderizado na tela como parte da interface do usuário.

Pense nas transformações em quatro classificações amplas: translação, rotação, dimensionamento e distorção (ou cisalhamento). Para fins de uso de APIs gráficas para alterar a aparência dos elementos da interface do usuário, geralmente é mais fácil criar transformações que definam apenas uma operação por vez. Portanto, o Tempo de Execução do Windows 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 Tempo de Execução do Windows que dão suporte a isso: CompositeTransform e TransformGroup. Em um CompositeTransform, as transformações são aplicadas nesta ordem: dimensionar, inclinar, girar, traduzir. Use TransformGroup em vez de CompositeTransform se quiser que as transformações sejam aplicadas 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, os cálculos de espaço disponível 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 transformar elementos que estão em uma célula Grid ou contêiner de layout semelhante que aloca espaço durante o 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 o 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 em estrela, talvez seja necessário alterar as propriedades do Centro ou declarar medidas de pixel fixas para o espaço do layout para garantir que o pai aloque 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 Tempo de Execução do Windows não dá suporte a uma propriedade LayoutTransform . (O Microsoft Silverlight também não tinha essa propriedade.)

Como alternativa, o Kit de Ferramentas da Comunidade do Windows oferece o LayoutTransformControl, que aplica transformações de Matriz a qualquer FrameworkElement do aplicativo.

Aplicar uma transformação em um elemento de interface do usuário

Ao aplicar uma transformação a um objeto, você 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 coordenadas local no qual esse objeto existe. Em seguida, a lógica e a operação de renderização (pós-layout) renderizam os espaços de coordenadas combinados, fazendo parecer que o objeto mudou de aparência e também potencialmente sua posição de layout (se TranslateTransform foi aplicado).

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

Sempre que você usar transformações com UIElement.RenderTransform, lembre-se de que há outra propriedade em UIElement que afeta como a transformação se comporta: 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 coordenadas relativo 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 CenterX e CenterY nas transformações. Observe que, se você aplicar 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 clique, um objeto ao qual uma transformação é aplicada continua a responder à 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 Rectangle 400 pixels lateralmente na interface do usuário, esse Rectangle responderá a eventos PointerPressed quando o usuário pressionar o ponto em que o Rectangle 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 z-index que afetem o teste de clique, a aplicação de uma transformação não faz diferença; O z-index 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 filho de um objeto Canvas você possa ajustar a ordem aplicando a propriedade anexada Canvas.ZIndex a elementos filho.

Outras propriedades de uma transformação

Animar uma transformação

Os objetos Transform podem ser animados. Para animar uma Transformação, 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. As 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 com storyboard.

Se você animar propriedades para produzir um efeito semelhante a uma transformação em termos da aparência visual líquida — por exemplo, animando a Largura e a Altura de um FrameworkElement em vez de aplicar um TranslateTransform — essas animações quase sempre serão 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 seria tratada como uma animação dependente.

Para direcionar a transformação, deve haver um Transform existente como o valor de 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 de ProgressRing usam valores animados de 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 Rectangle no lugar em torno de seu centro visual. Este exemplo nomeia o RotateTransform para que não precise de direcionamento de animação indireto, 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();
}

Justificar quadros de referência de coordenadas em runtime

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

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 coordenadas de referência para um elemento específico em vez do padrão do aplicativo. Essa abordagem simplesmente aplica uma transformação de conversão internamente e transforma os dados de coordenadas x-y para você quando cria o objeto PointerPoint retornado.

Descrever uma transformação matematicamente

Uma transformação pode ser descrita em termos de uma matriz de transformação. Uma matriz 3×3 é usada para descrever as transformações em um plano x-y bidimensional. As matrizes de transformação afim podem ser multiplicadas para formar qualquer número de transformações lineares, como rotação e inclinação (cisalhamento), seguidas de translação. A coluna final de uma matriz de transformação afim é 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 se você tiver um conhecimento matemático ou uma familiaridade com técnicas de programação gráfica que também usam matrizes para descrever transformações do espaço de coordenadas. Há uma classe derivada de Transform que 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 OffsetY 1

Qualquer transformação que você possa descrever com um objeto TranslateTransform, ScaleTransform, RotateTransform ou SkewTransform pode ser descrita igualmente por um MatrixTransform com um valor Matrix. Mas você normalmente usa apenas TranslateTransform e os outros porque as propriedades nessas classes de transformação são mais fáceis de conceituar do que definir os componentes vetoriais em uma matriz. Também é mais fácil animar as propriedades discretas das transformações; uma Matrix é 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 da 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 é equivalente a aplicar uma transformação de perspectiva fixa e uma ou mais transformações 3D ao elemento. Esse tipo de transformação é descrito com mais detalhes em efeitos de perspectiva 3D para a interface do usuário XAML.