共用方式為


彈性動畫

這篇文章說明如何在 WinUI 中使用 Spring NaturalMotionAnimations。

先決條件

在這裡,我們假設你已經熟悉這些文章中討論的概念:

為什麼是彈簧?

彈簧是我們每個人在人生中某個時刻都經歷過的常見運動體驗;從彈簧玩具到物理教室裡的彈簧綁磚體驗應有盡有。 彈簧的擺動常常會引發觀察者輕鬆愉快的情感反應。 因此,彈簧的運動能很好地轉化為應用程式介面,適合那些想要打造更生動的動作體驗的開發者,這種體驗比傳統的立方貝塞爾曲線更能吸引終端使用者。 在這些情況下,彈簧運動不僅能帶來更生動的動態體驗,也能吸引人們對新動畫或正在動畫內容的注意。 根據應用程式的品牌或動作語言,振盪會更明顯且可見,但在其他情況下則較為微妙。

彈簧動畫中的運動 三次方貝塞爾動畫中的運動

在你的 UI 中使用彈簧

如前所述,彈簧是整合進 WinUI 應用程式的好用動作,能帶來非常熟悉且充滿趣味的 UI 體驗。 彈簧在 UI 中常見的用途包括:

彈簧使用說明 視覺範例
讓動態體驗「鮮明」且看起來更有活力。 (動畫音階) 使用彈簧動畫進行縮放運動
讓視覺動態體驗更加細膩且充滿活力(動態偏移) 彈簧動畫中的偏移運動

在這些情況下,彈簧運動可以透過「彈跳到」並繞著新值振盪,或以初始速度繞著當前值振盪來觸發。

彈簧動畫振盪

定義你的彈簧運動

你可以透過使用 NaturalMotionAnimation API 來建立 Spring 體驗。 具體來說,你要用合成器裡的 Create* 方法來建立 SpringNaturalMotionAnimation。 接著你可以定義運動的以下性質:

  • DampingRatio – 表達動畫中使用彈簧運動的阻尼程度。
阻尼比值 說明
阻尼比 = 0 未阻尼時,彈簧會長時間擺動
0 < 阻尼比 < 1 阻尼不足的情況下,彈簧會從小幅度到大幅度地振蕩。
阻尼比 = 1 極度阻尼時,彈簧不會產生振盪。
阻尼比 > 1 過阻尼——彈簧會迅速以突然減速且無振盪的方式抵達目的地
  • 週期——彈簧完成一次振盪所需的時間。
  • 最終值/起始值——定義彈簧運動的起始與結束位置(若未定義,起始值及/或最終值為當前值)。
  • 初始速度——動作的程式化初始速度。

你也可以定義一組與 KeyFrameAnimations 相同的動作屬性:

  • 延遲時間 / 延遲操作方式
  • 停止行為

在常見的偏移量與比例/尺寸動畫中,Windows 設計團隊建議針對不同類型彈簧使用以下數值作為阻尼比與週期:

房產 普通春天 潮濕的春天 較少濕潤的春天
Offset 阻尼比 = 0.8
週期 = 50毫秒
阻尼比 = 0.85
週期 = 50毫秒
阻尼比 = 0.65
週期 = 60毫秒
比例/尺寸 阻尼比 = 0.7
週期 = 50毫秒
阻尼比 = 0.8
週期 = 50毫秒
阻尼比 = 0.6
週期 = 60毫秒

一旦您定義完屬性,便可以將 spring NaturalMotionAnimation 傳遞到 CompositionObject 的 StartAnimation 方法中,或是傳遞到 InteractionTracker InertiaModifier 的 Motion 屬性中。

範例

在這個範例中,你建立一個導航與畫布介面體驗,當使用者點擊展開按鈕時,導覽窗格會以彈簧般的振盪動作呈現。

點擊時的彈性動畫

首先在點擊事件中定義彈簧動畫,表示導航面板出現時的效果。 接著你用 InitialValueExpression 功能定義動畫屬性,再用 Expression 來定義 FinalValue。 你也會記錄窗格是否開啟,準備好後開始動畫。

private void Button_Clicked(object sender, RoutedEventArgs e)
{
    _springAnimation = _compositor.CreateSpringScalarAnimation();
    _springAnimation.DampingRatio = 0.75f;
    _springAnimation.Period = TimeSpan.FromSeconds(0.5);

    if (!_expanded)
    {
        _expanded = true;
        _propSet.InsertBoolean("expanded", true);
        _springAnimation.InitialValueExpression["FinalValue"] = "this.StartingValue + 250";
    }
    else
    {
        _expanded = false;
        _propSet.InsertBoolean("expanded", false);
        _springAnimation.InitialValueExpression["FinalValue"] = "this.StartingValue - 250";
    }

    _naviPane.StartAnimation("Offset.X", _springAnimation);
}

那如果你想把這個動作和輸入連結呢? 所以如果使用者滑走,窗格會以彈跳效果移出? 更重要的是,如果使用者滑動得更用力或更快,動作會根據使用者的速度來調整。

滑動時的彈簧效果

為此,你可以將相同的彈簧動畫傳入 InertiaModifier,並與 InteractionTracker 一起使用。 欲了解更多關於 InputAnimations 與 InteractionTracker 的資訊,請參閱 InteractionTracker 的自訂操作體驗。 假設這個程式碼範例中,你已經設定好 InteractionTracker 和 VisualInteractionSource。 我們將專注於建立能接收 NaturalMotionAnimation(彈簧)的慣性修正器。

// InteractionTracker and the VisualInteractionSource were previously set up.
// The open and close ScalarSpringAnimations were defined earlier.
private void SetupInput()
{
    // Define the InertiaModifier to manage the open motion.
    var openMotionModifier = InteractionTrackerInertiaNaturalMotion.Create(_compositor);

    // Use the open animation if the pane is not expanded.
    openMotionModifier.Condition = _compositor.CreateExpressionAnimation(
        "propSet.expanded == false");
    openMotionModifier.Condition.SetReferenceParameter("propSet", _propSet);
    openMotionModifier.NaturalMotion = _openSpringAnimation;

    // Define the InertiaModifier to manage the close motion.
    var closeMotionModifier = InteractionTrackerInertiaNaturalMotion.Create(_compositor);

    // Use the close animation if the pane is expanded.
    closeMotionModifier.Condition = _compositor.CreateExpressionAnimation(
        "propSet.expanded == true");
    closeMotionModifier.Condition.SetReferenceParameter("propSet", _propSet);
    closeMotionModifier.NaturalMotion = _closeSpringAnimation;

    _tracker.ConfigurePositionXInertiaModifiers(new InteractionTrackerInertiaNaturalMotion[]
    {
        openMotionModifier,
        closeMotionModifier,
    });

    // Take the InteractionTracker output and assign it to the pane.
    var exp = _compositor.CreateExpressionAnimation("-tracker.Position.X");
    exp.SetReferenceParameter("tracker", _tracker);

    ElementCompositionPreview.GetElementVisual(pageNavigation)
        .StartAnimation("Translation.X", exp);
}

這樣你的 UI 裡就同時有程式化和輸入驅動的彈簧動畫了!

總結來說,在你的應用程式中使用彈簧動畫的步驟如下:

  1. 從合成器建立你的 SpringAnimation。
  2. 如果你想要非預設值,請定義 SpringAnimation 的屬性:
    • 阻尼比
    • Period
    • 最終價值
    • 初始值
    • 初始速度
  3. 指派到目標對象。
    • 如果您正在為 CompositionObject 的屬性設置動畫,請將 SpringAnimation 作為參數傳遞給 StartAnimation。
    • 如果你想搭配輸入使用,可以將 InertiaModifier 的 NaturalMotion 屬性設定為 SpringAnimation。