以關聯為基礎的動畫
本文提供的簡短概觀,說明如何使用 Composition ExpressionAnimations 建立以關聯為基礎的動畫。
動態式以關聯為基礎的體驗
在應用程式中建置動作體驗時,有時候動作不是以時間為基礎,而是取決於另一個物件上的屬性。 KeyFrameAnimations 無法非常輕鬆地表達這些類型的動作體驗。 在這些特定執行個體中,動作不再需要是離散的,也不再需要預先定義。 相反地,動作可以根據與其他物件屬性的關聯性,加以動態調整。 例如,您可以根據物件的水平位置,以動畫顯示物件的不透明度。 其他範例包括動作體驗,例如黏性標頭和視差。
這些類型的動作體驗可讓您建立更有連結感的 UI,而不再感覺孤單且獨立。 對使用者而言,這會留下動態 UI 體驗的印象。
使用 ExpressionAnimations
若要建立以關聯為基礎的動作體驗,您可以使用 ExpressionAnimation 類型。 ExpressionAnimations (或簡稱運算式),是一種新的動畫類型,可讓您表達數學關聯性 – 系統會使用這個關聯性,來計算每個畫面的動畫屬性值。 換句話說,運算式只是一個數學方程式,可定義每個畫面之動畫屬性的需求值。 運算式是一個非常多用途的元件,可用於各種不同的案例,包括:
- 相對大小、位移動畫。
- 黏性標頭、使用 ScrollViewer 的視差。 (請參閱增強現有的 ScrollViewer 體驗。)
- 使用 InertiaModifiers 和 InteractionTracker 的貼齊點。 (請參閱使用慣性修飾詞建立貼齊點。)
使用 ExpressionAnimations 時,有幾件事值得事先說明:
- 永不結束 – 與其同層級的 KeyFrameAnimation 不同,運算式沒有持續時間限制。 由於運算式是數學關聯性,所以它們是不斷「執行」的動畫。 您可以選擇是否有選項可停止這些動畫。
- 不斷執行,但不會一直評估 – 對於不斷執行的動畫,效能始終是必要考量。 不過也不需要擔心,系統就足夠聰明,運算式只會在其任何輸入或參數變更時重新評估。
- 解析為正確的物件類型 – 因為運算式是數學關聯性,所以請務必確定,要定義運算式之方程式所解析的類型,與動畫所鎖定的屬性相同。 例如,如果以動畫顯示位移,則運算式應該解析為 Vector3 類型。
運算式的元件
建置運算式的數學關聯性時,有幾個核心元件:
- 參數 – 代表常數值或其他組合物件的參考值。
- 數學運算子 – 運用加號 (+)、減號 (-)、乘號 (*)、除號 (/) 等一般數學運算子,將參數聯結在一起,形成方程式。 此外也包括條件運算子,例如大於 (>)、equal (==)、三元運算子 (condition ? ifTrue : ifFalse) 等。
- 數學函式 – 以 System.Numerics 為基礎的數學函式/快捷方式。 如需支援函式的完整清單,請參閱 ExpressionAnimation。
運算式也支援一組關鍵詞 – 只在 ExpressionAnimation 系統中具有不同意義的特殊片語。 這些 (以及數學函式的完整清單) 都列在 ExpressionAnimation 文件中。
使用 ExpressionBuilder 建立運算式
在 UWP 應用程式中建置運算式有兩個選項:
- 透過官方的公用 API,將方程式建置為字串。
- 透過 Windows Community Toolkit 隨附的 ExpressionBuilder 工具,在型別安全物件模型中建置方程式。
為了本文件方便說明起見,我們將使用 ExpressionBuilder 來定義運算式。
參數
參數是組成運算式的核心。 參數可分為兩種:
- 常數:這些是代表型別 System.Numeric 變數的參數。 這些參數會在動畫啟動時取得指派的值一次。
- 參考:這些是代表 CompositionObjects 參考的參數 – 這些參數會在動畫啟動後,持續取得更新其值。
一般而言,參考是運算式輸出可以如何動態改變的主要層面。 當這些參考改變時,運算式的輸出也會隨之改變。 如果您使用字串建立運算式,或在範本化案例中使用它們 (使用運算式以多個 CompositionObjects 為目標),則必須命名並設定參數的值。 如需詳細資訊,請參閱「範例」區段。
使用 KeyFrameAnimations
運算式也可和 KeyFrameAnimations 搭配使用。 在這些執行個體中,您想要使用運算式在某個時間點定義 KeyFrame 的值 – 這些 KeyFrame 型別就稱為 ExpressionKeyFrames。
KeyFrameAnimation.InsertExpressionKeyFrame(Single, String)
KeyFrameAnimation.InsertExpressionKeyFrame(Single, ExpressionNode)
不過,與 ExpressionAnimations 不同,只有在 KeyFrameAnimation 啟動時,才會評估 ExpressionKeyFrames。 請記住,不要傳入 ExpressionAnimation 作為 KeyFrame 的值,要傳入字串 (如果您使用的是 ExpressionBuilder,則要傳入 ExpressionNode)。
範例
現在讓我們逐步解說使用運算式的範例,特別是來自 Windows UI 範例庫的 PropertySet 範例。 我們將探討管理藍球軌道運動行為的運算式。
有三個登場元件構成整體體驗:
- KeyFrameAnimation,以動畫顯示紅球的 Y 位移。
- 具有 Rotation 屬性的 PropertySet,可協助驅動由另一個 KeyFrameAnimation 產生動畫的軌道。
- ExpressionAnimation,參考紅球位移和旋轉屬性來驅動藍球位移,以維持完美的軌道。
我們會將重點放在第 3 點中定義的 ExpressionAnimation。 我們也會使用 ExpressionBuilder 類別來建構此運算式。 最後會列出透過字串建置此體驗所使用的程式碼複本。
在此方程式中,您需要從 PropertySet 參考兩個屬性;一個是中心點位移,另一個是旋轉。
var propSetCenterPoint =
_propertySet.GetReference().GetVector3Property("CenterPointOffset");
// This rotation value will animate via KFA from 0 -> 360 degrees
var propSetRotation = _propertySet.GetReference().GetScalarProperty("Rotation");
接下來,您需要定義負責實際軌道旋轉的 Vector3 元件。
var orbitRotation = EF.Vector3(
EF.Cos(EF.ToRadians(propSetRotation)) * 150,
EF.Sin(EF.ToRadians(propSetRotation)) * 75, 0);
注意
EF
是簡略 “using” 標記法,用來定義 ExpressionFunctions。
using EF = Microsoft.Toolkit.Uwp.UI.Animations.Expressions.ExpressionFunctions;
最後,將這些元件結合在一起,並參考紅球的位置,以定義數學關聯性。
var orbitExpression = redSprite.GetReference().Offset + propSetCenterPoint + orbitRotation;
blueSprite.StartAnimation("Offset", orbitExpression);
讓我們來假設,如果您想要使用這個相同的運算式,但還要結合其他兩個視覺效果,也就是 2 組軌道圓形。 使用 CompositionAnimations,您可以重複使用動畫,並以多個 CompositionObjects 為目標。 當您使用此運算式來處理其他軌道的情況時,唯一需要變更的部分,只有視覺效果的參考。 我們稱之為範本化。
在此情況下,您可以修改稍早建置的運算式。 您不是「取得」CompositionObject 的參考,而是使用名稱建立參考,然後指派不同的值:
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);
如果您是透過公用 API 使用字串來定義運算式,以下是所使用的程式碼。
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);