Partilhar via


Animações baseadas em relações

Este artigo apresenta uma breve visão geral de como criar animações baseadas em relações usando o Composition ExpressionAnimations.

Experiências dinâmicas baseadas em relações

Ao construir experiências de movimento numa aplicação, há momentos em que o movimento não é baseado no tempo, mas sim dependente de uma propriedade noutro objeto. As KeyFrameAnimations não conseguem expressar este tipo de experiências de movimento muito facilmente. Nestes casos específicos, o movimento já não precisa de ser discreto e pré-definido. Em vez disso, o movimento pode adaptar-se dinamicamente com base na sua relação com as propriedades de outros objetos. Por exemplo, pode animar a opacidade de um objeto com base na sua posição horizontal. Outros exemplos incluem experiências de movimento como Sticky Headers e Parallax.

Este tipo de experiências de movimento permite-lhe criar uma interface que se sente mais conectada, em vez de parecer singular e independente. Para o utilizador, isto dá a impressão de uma experiência de interface dinâmica.

Círculo orbital

Vista de lista com paralaxe

Utilização do ExpressionAnimations

Para criar experiências de movimento baseadas em relações, utiliza-se o tipo ExpressionAnimation. ExpressionAnimations (ou Expressions, para abreviar) são um novo tipo de animação que permite expressar uma relação matemática – uma relação que o sistema utiliza para calcular o valor de uma propriedade de animação em cada frame. Por outras palavras, as expressões são simplesmente uma equação matemática que define o valor desejado de uma propriedade de animação por frame. As expressões são um componente muito versátil que pode ser usado numa grande variedade de cenários, incluindo:

Ao trabalhar com ExpressionAnimations, há algumas coisas que vale a pena mencionar desde o início:

  • Never Ending – ao contrário do seu irmão KeyFrameAnimation, Expressions não tem uma duração finita. Como as Expressões são relações matemáticas, são animações que estão constantemente "a correr". Tens a opção de parar estas animações se quiseres.
  • Em execução, mas nem sempre avaliando seu desempenho – o desempenho é sempre uma preocupação com animações que estão constantemente em execução. Não se preocupe, o sistema é bastante inteligente para que a Expressão só seja reavaliada se alguma das suas entradas ou parâmetros tiverem alterado.
  • Resolver para o tipo de objeto correto – Como as Expressões são relações matemáticas, é importante garantir que a equação que define a Expressão resolve para o mesmo tipo da propriedade que está a ser alvo da animação. Por exemplo, se estiveres a animar o Offset, a tua Expressão deve ser resolvida para um tipo Vector3.

Componentes de uma expressão

Ao construir a relação matemática de uma Expressão, existem vários componentes fundamentais:

  • Parâmetros – valores que representam valores constantes ou referências a outros objetos de Composição.
  • Operadores Matemáticos – os operadores matemáticos típicos mais(+), menos(-), multiplicação(*), divisão(/) que unem parâmetros para formar uma equação. Também estão incluídos operadores condicionais como maior que(>), igual(==), operador ternário (condição ? seVerdadeiro : seFalso), etc.
  • Funções Matemáticas – funções/atalhos matemáticos baseados em System.Numerics. Para uma lista completa de funções suportadas, veja ExpressionAnimation.

As expressões também suportam um conjunto de palavras-chave – frases especiais que têm significado distinto apenas dentro do sistema ExpressionAnimation. Estas estão listadas (juntamente com a lista completa de funções matemáticas) na documentação do ExpressionAnimation .

Criar Expressões com o ExpressionBuilder

Existem duas opções para criar Expressões na sua aplicação WinUI:

  1. Constrói a equação como uma string através da API oficial e pública.
  2. Construa a equação num modelo de objetos seguro para tipos através da ferramenta ExpressionBuilder incluída no Windows Community Toolkit.

Para efeitos deste documento, definiremos as nossas Expressões usando o ExpressionBuilder.

Parâmetros

Os parâmetros constituem o núcleo de uma Expressão. Existem dois tipos de parâmetros:

  • Constantes: são parâmetros que representam variáveis System.Numeric tipadas. Estes parâmetros recebem os seus valores atribuídos uma vez quando a animação é iniciada.
  • Referências: são parâmetros que representam referências a CompositionObjects – estes parâmetros recebem continuamente os seus valores atualizados após o início de uma animação.

Em geral, as Referências são o principal aspeto de como a saída de uma Expressão pode mudar dinamicamente. À medida que estas referências mudam, a saída da expressão muda consequentemente. Se criares a tua Expressão com Strings ou as usares num cenário de templates (usando a tua Expression para direcionar múltiplos CompositionObjects), terás de nomear e definir os valores dos teus parâmetros. Consulte a secção de Exemplos para mais informações.

Trabalhando com KeyFrameAnimations

Expressões também podem ser usadas com KeyFrameAnimations. Nestes casos, deve-se usar uma Expressão para definir o valor de um KeyFrame num determinado momento – estes tipos de KeyFrames são chamados de ExpressionKeyFrames.

KeyFrameAnimation.InsertExpressionKeyFrame(Single, String)
KeyFrameAnimation.InsertExpressionKeyFrame(Single, ExpressionNode)

No entanto, ao contrário das ExpressionAnimations, as ExpressionKeyFrames são avaliadas apenas uma vez quando a KeyFrameAnimation é iniciada. Tenha em mente que não passa um ExpressionAnimation como valor do KeyFrame, mas sim como uma string (ou um ExpressionNode, se estiver a usar o ExpressionBuilder).

Exemplo

Vamos agora passar por um exemplo de utilização de Expressões, especificamente o exemplo PropertySet da Galeria de Exemplos da interface do Windows. Vamos examinar a expressão que gere o comportamento de movimento orbital da bola azul.

Círculo orbital

Existem três componentes em jogo para a experiência global:

  1. Uma animação KeyFrameAnimation, que anima o desvio Y da bola vermelha.
  2. Um PropertySet com uma propriedade Rotation que ajuda a conduzir a órbita, animado por outro KeyFrameAnimation.
  3. Uma ExpressionAnimation que conduz o Deslocamento da bola azul, referenciando o Deslocamento da Bola Vermelha e a propriedade de Rotação para manter uma órbita perfeita.

Vamos focar-nos no ExpressionAnimation definido no #3. Também iremos usar as classes ExpressionBuilder para construir esta Expressão. Uma cópia do código usado para construir esta experiência via Strings está listada no final.

Nesta equação, há duas propriedades que precisa de referenciar a partir do PropertySet; um é o deslocamento do ponto central e o outro é a rotação.

var propSetCenterPoint =
_propertySet.GetReference().GetVector3Property("CenterPointOffset");

// This rotation value will animate via KFA from 0 -> 360 degrees
var propSetRotation = _propertySet.GetReference().GetScalarProperty("Rotation");

De seguida, precisa de definir o componente Vector3 que tem em conta a rotação orbital real.

var orbitRotation = EF.Vector3(
    EF.Cos(EF.ToRadians(propSetRotation)) * 150,
    EF.Sin(EF.ToRadians(propSetRotation)) * 75, 0);

Observação

EF é uma forma abreviada de "usar" a notação para definir ExpressionFunctions a partir da tua biblioteca de construtores de expressões WinUI.

Finalmente, combine estes componentes e faça referência à posição da Bola Vermelha para definir a relação matemática.

var orbitExpression = redSprite.GetReference().Offset + propSetCenterPoint + orbitRotation;
blueSprite.StartAnimation("Offset", orbitExpression);

Numa situação hipotética, e se quisesses usar a mesma expressão mas com outros dois elementos visuais, ou seja, dois conjuntos de círculos a orbitar. Com o CompositionAnimations, pode reutilizar a animação e direcionar vários CompositionObjects. A única coisa que precisas de mudar quando usas esta Expressão para o caso adicional de órbita é a referência ao Visual. Chamamos a isto templação.

Neste caso, modifica a Expressão que construiu anteriormente. Em vez de "obter" uma referência para o CompositionObject, cria uma referência com um nome e depois atribui valores diferentes:

var orbitExpression = ExpressionValues.Reference.CreateVisualReference("orbitRoundVisual");
orbitExpression.SetReferenceParameter("orbitRoundVisual", redSprite);
blueSprite.StartAnimation("Offset", orbitExpression);
// Later on … use same Expression to assign to another orbiting Visual
orbitExpression.SetReferenceParameter("orbitRoundVisual", yellowSprite);
greenSprite.StartAnimation("Offset", orbitExpression);

Aqui está o código se definiu a sua Expressão com Strings através da API pública.

ExpressionAnimation expressionAnimation = compositor.CreateExpressionAnimation("visual.Offset + " +
    "propertySet.CenterPointOffset + " +
    "Vector3(cos(ToRadians(propertySet.Rotation)) * 150," + "sin(ToRadians(propertySet.Rotation)) * 75, 0)");
    
var propSetCenterPoint = _propertySet.GetReference().GetVector3Property("CenterPointOffset");
var propSetRotation = _propertySet.GetReference().GetScalarProperty("Rotation");
expressionAnimation.SetReferenceParameter("propertySet", _propertySet);
expressionAnimation.SetReferenceParameter("visual", redSprite);