Animações baseadas em relações
Este artigo fornece uma breve visão geral de como fazer animações baseadas em relação usando Composition ExpressionAnimations.
Experiências Dinâmicas Baseadas em Relação
Ao criar experiências de movimento em um aplicativo, há momentos em que o movimento não é baseado em tempo, mas sim dependente de uma propriedade em outro objeto. KeyFrameAnimations não são capazes de expressar esses tipos de experiências de movimento com muita facilidade. Nesses casos específicos, o movimento não precisa mais ser discreto e predefinido. Em vez disso, o movimento pode se adaptar dinamicamente com base em sua relação com outras propriedades do objeto. Por exemplo, você pode animar a opacidade de um objeto com base em sua posição horizontal. Outros exemplos incluem experiências de movimento como Sticky Headers e Parallax.
Esses tipos de experiências de movimento permitem que você crie uma interface do usuário que pareça mais conectada, em vez de parecer singular e independente. Para o usuário, isso dá a impressão de uma experiência de interface do usuário dinâmica.
Usando ExpressionAnimations
Para criar experiências de movimento baseadas em relação, use 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 usa para calcular o valor de uma propriedade de animação a cada quadro. Dito de outra forma, as expressões são simplesmente uma equação matemática que define o valor desejado de uma propriedade de animação por quadro. As expressões são um componente muito versátil que pode ser usado em uma ampla variedade de cenários, incluindo:
- Tamanho relativo, animações de deslocamento.
- Cabeçalhos fixos, paralaxe com ScrollViewer. (Veja Aprimore as experiências existentes do ScrollViewer.)
- Pontos de ajuste com InertiaModifiers e InteractionTracker. (Veja Crie pontos de snap com modificadores de inércia.)
Ao trabalhar com ExpressionAnimations, há algumas coisas que vale a pena mencionar antecipadamente:
- Never Ending – ao contrário de seu irmão KeyFrameAnimation, as expressões não têm uma duração finita. Como as expressões são relações matemáticas, elas são animações que estão constantemente "em execução". Você tem a opção de interromper essas animações, se desejar.
- Executando, mas nem sempre avaliando – o desempenho é sempre uma preocupação com animações que estão em constante execução. Não precisa se preocupar, porém, o sistema é inteligente o suficiente para que a Expressão só reavalie se alguma de suas entradas ou parâmetros tiver sido alterado.
- Resolvendo 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 seja resolvida para o mesmo tipo da propriedade que está sendo direcionada pela animação. Por exemplo, se estiver animando Offset, sua Expression deverá ser resolvida para um tipo Vector3.
Componentes de uma expressão
Ao criar a relação matemática de uma expressão, há vários componentes principais:
- 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(-), multiplicar(*), dividir(/) 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 ? ifTrue : ifFalse), etc.
- Funções matemáticas – funções/atalhos matemáticos baseados em System.Numerics. Para obter uma lista completa de funções com suporte, consulte ExpressionAnimation.
As expressões também dão suporte a um conjunto de palavras-chave – frases especiais que têm significado distinto apenas dentro do sistema ExpressionAnimation. Eles estão listados (junto com a lista completa de funções matemáticas) na documentação do ExpressionAnimation .
Criando expressões com o ExpressionBuilder
Há duas opções para criar expressões em seu aplicativo UWP:
- Crie a equação como uma string por meio da API pública oficial.
- Crie a equação em um modelo de objeto fortemente tipado por meio da ferramenta ExpressionBuilder incluída no Windows Community Toolkit.
Para fins deste documento, definiremos nossas expressões usando o ExpressionBuilder.
Parâmetros
Os parâmetros compõem o núcleo de uma expressão. Existem dois tipos de parâmetros:
- Constantes: são parâmetros que representam variáveis System.Numeric digitadas. Esses parâmetros recebem seus valores atribuídos uma vez quando a animação é iniciada.
- Referências: são parâmetros que representam referências a CompositionObjects – esses parâmetros têm seus valores atualizados continuamente após o início de uma animação.
Em geral, as referências são o principal aspecto de como a saída de uma expressão pode mudar dinamicamente. À medida que essas referências mudam, a saída da Expressão muda como resultado. Se você criar sua Expressão com Strings ou usá-las em um cenário de modelagem (usando sua Expressão para direcionar vários CompositionObjects), precisará nomear e definir os valores de seus parâmetros. Veja a seção Exemplo para mais informações.
Trabalhando com KeyFrameAnimations
As expressões também podem ser usadas com KeyFrameAnimations. Nesses casos, você deseja usar uma expressão para definir o valor de um KeyFrame em um ponto de tempo – esses tipos de KeyFrames são chamados de ExpressionKeyFrames.
KeyFrameAnimation.InsertExpressionKeyFrame(Single, String)
KeyFrameAnimation.InsertExpressionKeyFrame(Single, ExpressionNode)
No entanto, ao contrário de ExpressionAnimations, ExpressionKeyFrames são avaliados apenas uma vez quando o KeyFrameAnimation é iniciado. Lembre-se de que você não passa um ExpressionAnimation como o valor do KeyFrame, mas sim uma cadeia de caracteres (ou um ExpressionNode, se você estiver usando ExpressionBuilder).
Exemplo
Vamos agora examinar um exemplo de uso de Expressões, especificamente o exemplo de PropertySet da Galeria de Exemplos da Interface do Usuário do Windows. Veremos a expressão que gerencia o comportamento do movimento da órbita da bola azul.
Existem três componentes em jogo para a experiência total:
- Um KeyFrameAnimation, animando o Deslocamento Y da bola vermelha.
- Um PropertySet com uma propriedade Rotation que ajuda a conduzir a órbita, animada por outro KeyFrameAnimation.
- Um ExpressionAnimation que orienta o Offset da bola azul referenciando o Deslocamento da Bola Vermelha e a propriedade Rotation para manter uma órbita perfeita.
Vamos nos concentrar no ExpressionAnimation definido em #3. Também usaremos as classes ExpressionBuilder para construir essa expressão. Uma cópia do código usado para criar essa experiência por meio de Strings é listada no final.
Nesta equação, há duas propriedades que você precisa referenciar do PropertySet; um é um 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");
Em seguida, você precisa definir o componente Vector3 que representa 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 notação abreviada "using" para definir ExpressionFunctions.
using EF = Microsoft.Toolkit.Uwp.UI.Animations.Expressions.ExpressionFunctions;
Finalmente, combine esses 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);
Em uma situação hipotética, e se você quisesse usar essa mesma expressão, mas com dois outros visuais, ou seja, 2 conjuntos de círculos orbitais. Com CompositionAnimations, você pode reutilizar a animação e direcionar vários CompositionObjects. A única coisa que você precisa alterar ao usar essa Expressão para o caso de órbita adicional é a referência ao Visual. Chamamos isso de modelo.
Nesse caso, você modifica a expressão criada anteriormente. Em vez de "obter" uma referência ao CompositionObject, você cria uma referência com um nome e 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 você definiu sua expressão com cadeias de caracteres por meio 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);