Animazioni basate sulle relazioni

Questo articolo offre una breve panoramica di come creare animazioni basate sulle relazioni usando Composition ExpressionAnimation.

Esperienze basate sulle relazioni dinamiche

Quando si creano esperienze di movimento in un'app, in alcuni casi il movimento non si basa sul tempo, ma dipende piuttosto da una proprietà su un altro oggetto. Le KeyFrameAnimation non sono in grado di esprimere questi tipi di esperienze di movimento molto facilmente. In questi casi specifici, il movimento non deve essere discreto e predefinito. Il movimento può invece adattarsi dinamicamente in base alla relazione con altre proprietà dell'oggetto. Ad esempio, è possibile animare l'opacità di un oggetto in base alla sua posizione orizzontale. Altri esempi includono esperienze di movimento come intestazioni permanenti e parallasse.

Questi tipi di esperienze di movimento consentono di creare un'interfaccia utente più connessa e meno singolare e indipendente. Per l'utente, questo dà l'impressione di un'esperienza di interfaccia utente dinamica.

Orbiting circle

List view with parallax

Uso di ExpressionAnimation

Per creare esperienze di movimento basate sulle relazioni, usare il tipo ExpressionAnimation. ExpressionAnimation (o expression, per brevità) sono un nuovo tipo di animazione che consente di esprimere una relazione matematica, ovvero una relazione usata dal sistema per calcolare il valore di una proprietà di animazione a ogni fotogramma. In altre parole, le Expression sono semplicemente un'equazione matematica che definisce il valore desiderato di una proprietà di animazione per fotogramma. Le expression sono un componente molto versatile che può essere usato in un'ampia gamma di scenari, tra cui:

Quando si lavora con ExpressionAnimation, esistono due aspetti che vale la pena menzionare subito:

  • Durata illimitata: a differenza del suo elemento di pari livello KeyFrameAnimation, le expression non hanno una durata limitata. Poiché le expression sono relazioni matematiche, sono animazioni costantemente "in esecuzione". È possibile scegliere di arrestare queste animazioni.
  • Esecuzione, ma non sempre valutazione: le prestazioni sono sempre un problema con animazioni costantemente in esecuzione. Ma non c'è da preoccuparsi, il sistema è abbastanza intelligente da riconoscere che l'expression rivaluta solo se uno dei relativi input o parametri è stato modificato.
  • Risoluzione del tipo di oggetto corretto: poiché le expression sono relazioni matematiche, è importante assicurarsi che l'equazione che definisce l'expression venga risolta nello stesso tipo della proprietà di destinazione dell'animazione. Ad esempio, nel caso dell'animazione di Offset, l'expression deve essere risolta in un tipo Vector3.

Componenti di un'expression

Quando si compila la relazione matematica di un'expression, esistono diversi componenti principali:

  • Parametri: valori che rappresentano valori costanti o riferimenti ad altri oggetti Composition.
  • Operatori matematici: tipici operatori matematici plus(+), minus(-), multiply(*), divide(/) che uniscono i parametri per formare un'equazione. Sono inclusi anche operatori condizionali come greater than(>), equal(==), operatore ternario (condizione ? ifTrue: ifFalse) e così via.
  • Funzioni matematiche: funzioni matematiche/collegamenti basati su System.Numerics. Per un elenco completo delle funzioni supportate, vedere ExpressionAnimation.

Le expression supportano anche un set di parole chiave: frasi speciali con un significato distinto solo all'interno del sistema ExpressionAnimation. Sono presenti (insieme all'elenco completo delle funzioni matematiche) nella documentazione di ExpressionAnimation.

Creazione di expression con ExpressionBuilder

Sono disponibili due opzioni per la compilazione di expression nell'app UWP:

  1. Compilare l'equazione come stringa tramite l'API pubblica ufficiale.
  2. Compilare l'equazione in un modello a oggetti indipendente dai tipi tramite lo strumento ExpressionBuilder incluso in Windows Community Toolkit.

Ai fini di questo documento, verranno definite le expression usando ExpressionBuilder.

Parametri

I parametri costituiscono il nucleo di un'expression. Sono disponibili due tipi di parametri:

  • Costanti: parametri che rappresentano variabili System.Numeric. Questi parametri ottengono i valori assegnati una volta all'avvio dell'animazione.
  • Riferimenti: parametri che rappresentano riferimenti a CompositionObjects. Questi parametri ottengono continuamente i relativi valori aggiornati dopo l'avvio di un'animazione.

In generale, i riferimenti sono l'aspetto principale per il modo in cui l'output di un'expression può cambiare dinamicamente. Quando questi riferimenti cambiano, l'output dell'expression cambia di conseguenza. Se si crea l'expression con stringhe o le si usa in uno scenario di creazione di modelli (usando l'expression per definire più oggetti CompositionObject), è necessario assegnare un nome e impostare i valori dei parametri. Per altre informazioni, vedi la sezione Esempi.

Uso di KeyFrameAnimation

Le expression sono usabili anche con KeyFrameAnimation. In questi casi si desidera usare un'expression per definire il valore di un fotogramma chiave alla volta. Questi tipi di fotogrammi chiave sono denominati ExpressionKeyFrames.

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

Tuttavia, a differenza di ExpressionAnimation, ExpressionKeyFrames viene valutato solo una volta quando viene avviato KeyFrameAnimation. Tenere presente che non si passa ExpressionAnimation come valore del fotogramma chiave, ma come stringa (o ExpressionNode, se si usa ExpressionBuilder).

Esempio

Verrà ora illustrato un esempio di uso di expression, in particolare l'esempio PropertySet della raccolta di esempi dell'interfaccia utente di Windows. Si esaminerà l'expression che gestisce il comportamento del movimento orbitale della palla blu.

Orbiting circle

Vi sono tre componenti in gioco per l'esperienza totale:

  1. KeyFrameAnimation, che anima l'offset Y della palla rossa.
  2. PropertySet con una proprietà Rotation che consente di guidare l'orbita, animata da un altro KeyFrameAnimation.
  3. ExpressionAnimation che guida l'offset della palla blu che fa riferimento all'offset della palla rossa e alla proprietà Rotation per mantenere un'orbita perfetta.

Ci concentreremo sull'ExpressionAnimation definita nel file #3. Verranno inoltre usati le classi ExpressionBuilder per costruire questa expression. Alla fine viene elencata una copia del codice usato per compilare questa esperienza tramite stringhe.

In questa equazione sono presenti due proprietà a cui è necessario fare riferimento da PropertySet; uno è un offset del punto centrale e l'altro è la rotazione.

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

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

Successivamente, è necessario definire il componente Vector3 che rappresenta l'effettiva rotazione orbitale.

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

Nota

EF è una notazione abbreviata per definire ExpressionFunctions.

using EF = Microsoft.Toolkit.Uwp.UI.Animations.Expressions.ExpressionFunctions;

Infine, combinare questi componenti e fare riferimento alla posizione della palla rossa per definire la relazione matematica.

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

In una situazione ipotetica, vediamo cosa accade se si desidera usare questa stessa expression ma con altri due oggetti visivi, vale a dire 2 set di cerchi orbitanti. Con CompositionAnimation, è possibile riutilizzare l'animazione e scegliere come destinazione più CompositionObject. L'unica cosa da modificare quando si usa questa expression per il caso dell'orbita aggiuntiva è il riferimento all'oggetto visivo. Questo viene chiamato modello o templating.

In questo caso, si modifica l'expression creata in precedenza. Invece di "ottenere" un riferimento a CompositionObject, si crea un riferimento con un nome e quindi si assegnano valori diversi:

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);

Di seguito è riportato il codice se è stata definita l'expression con stringhe tramite l'API pubblica.

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);