使用慣性修飾詞建立貼齊點

在本文中,我們會深入探討如何使用 InteractionTracker 的 InertiaModifier 功能,來建立貼齊至指定點的動作體驗。

必要條件

在這裡,我們假設您已熟悉下列文章中討論的概念:

什麼是貼齊點?為什麼它們很有用?

建置自訂操作體驗時,在 InteractionTracker 一定會停留的可捲動/可縮放畫布內建立特殊的位置點,有時候會相當實用。 這些通常稱為貼齊點

請注意下列範例中,捲動如何將 UI 留在不同影像之間的尷尬位置:

Scrolling without snap points

如果您新增貼齊點,當您在影像之間停止捲動時,它們會「貼齊」到指定的位置。 有了貼齊點,它可讓捲動影像的體驗更簡潔且回應更靈敏。

Scrolling with a single snap point

InteractionTracker 和 InertiaModifiers

使用 InteractionTracker 建立自訂操作體驗時,您可以使用 InertiaModifiers 來建立貼齊點動作體驗。 InertiaModifiers 基本上是一種定義方法,可讓您定義在進入慣性狀態時,InteractionTracker 到達其目的地的位置或方式。 您可以套用 InertiaModifier 來影響 InteractionTracker 的 X 或 Y 位置,或是 Scale 属性。

InertiaModifiers 有 3 種類型:

  • InteractionTrackerInertiaRestingValue – 在互動或程式碼控制速度之後,修改最終停止位置的方法。 預先定義的動作會將 InteractionTracker 帶到該位置。
  • InteractionTrackerInertiaMotion – 定義特定動作 InteractionTracker 的方法,會在互動或程式碼控制速度之後執行。 最終位置將由此動作衍生而來。
  • InteractionTrackerInertiaNaturalMotion – 在互動或程式碼控制速度之後,定義最終停止位置的方法,但具有以物理為基礎的動畫 (NaturalMotionAnimation)。

輸入慣性時,InteractionTracker 會評估指派給它的每一個 InertiaModifier,並判斷其中是否有可適用的項目。 這表示您可以建立多個 InertiaModifier 並將他們指派給 InteractionTracker,但是,在定義每個項目時,您需要執行下列動作:

  1. 定義 Condition – 這是一個運算式,定義此特定 InertiaModifier 的條件陳述式應該在何時發生。 這通常需要查看 InteractionTracker 的 NaturalRestingPosition (目的地已指定預設慣性)。
  2. 定義 RestingValue/Motion/NaturalMotion – 定義當符合條件時,實際會執行的 Resting Value Expression、Motion Expression 或 NaturalMotionAnimation。

注意

當 InteractionTracker 進入慣性時,只會評估一次 InertiaModifiers 的條件層面。 不過,只有在處理 InertiaMotion 的時候,動作運算式會針對條件為 true 的修飾詞來評估每個畫面。

範例

現在讓我們看看,如何使用 InertiaModifiers 來建立一些貼齊點體驗,以重新建立影像的捲動畫布。 在此範例中,每個操作都是為了可能要移動完單一影像,這通常稱為「單一強制貼齊點」。

讓我們從設定 InteractionTracker、VisualInteractionSource 以及即將運用 InteractionTracker 位置的 Expression 這三項開始。

private void SetupInput()
{
    _tracker = InteractionTracker.Create(_compositor);
    _tracker.MinPosition = new Vector3(0f);
    _tracker.MaxPosition = new Vector3(3000f);

    _source = VisualInteractionSource.Create(_root);
    _source.ManipulationRedirectionMode =
        VisualInteractionSourceRedirectionMode.CapableTouchpadOnly;
    _source.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;
    _tracker.InteractionSources.Add(_source);

    var scrollExp = _compositor.CreateExpressionAnimation("-tracker.Position.Y");
    scrollExp.SetReferenceParameter("tracker", _tracker);
    ElementCompositionPreview.GetElementVisual(scrollPanel).StartAnimation("Offset.Y", scrollExp);
}

接下來,因為單一強制貼齊點行為會向上或向下移動內容,所以您將需要兩個不同的慣性修飾詞:一個將可捲動的內容向上移動,另一個將內容向下移動。

// Snap-Point to move the content up
var snapUpModifier = InteractionTrackerInertiaRestingValue.Create(_compositor);
// Snap-Point to move the content down
var snapDownModifier = InteractionTrackerInertiaRestingValue.Create(_compositor);

是否要貼齊或向下,取決於 InteractionTracker 是否會自然落在相對於貼齊距離的位置內 – 也就是貼齊位置之間的距離。 如果超過中間點,則往下貼齊,否則就往上貼齊。 (在此範例,您將貼齊距離儲存在 PropertySet 中)

// Is NaturalRestingPosition less than the halfway point between Snap Points?
snapUpModifier.Condition = _compositor.CreateExpressionAnimation(
"this.Target.NaturalRestingPosition.y < (this.StartingValue - " + 
"mod(this.StartingValue, prop.snapDistance) + prop.snapDistance / 2)");
snapUpModifier.Condition.SetReferenceParameter("prop", _propSet);
// Is NaturalRestingPosition greater than the halfway point between Snap Points?
snapDownModifier.Condition = _compositor.CreateExpressionAnimation(
"this.Target.NaturalRestingPosition.y >= (this.StartingValue - " + 
"mod(this.StartingValue, prop.snapDistance) + prop.snapDistance / 2)");
snapDownModifier.Condition.SetReferenceParameter("prop", _propSet);

此圖表以視覺方式描述所發生的邏輯:

Inertia modifier diagram

現在,您只需要為每個 InertiaModifier 定義 Resting Values:是要將 InteractionTracker 的位置移至上一個貼齊位置,或是下一個位置。

snapUpModifier.RestingValue = _compositor.CreateExpressionAnimation(
"this.StartingValue - mod(this.StartingValue, prop.snapDistance)");
snapUpModifier.RestingValue.SetReferenceParameter("prop", _propSet);
snapDownModifier.RestingValue = _compositor.CreateExpressionAnimation(
"this.StartingValue + prop.snapDistance - mod(this.StartingValue, " + 
"prop.snapDistance)");
snapDownModifier.RestingValue.SetReferenceParameter("prop", _propSet);

最後,將 InertiaModifiers 新增至 InteractionTracker。 現在當 InteractionTracker 進入其 InertiaState 時,它會檢查您的 InertiaModifier 條件,以查看其位置是否應該修改。

var modifiers = new InteractionTrackerInertiaRestingValue[] { 
snapUpModifier, snapDownModifier };
_tracker.ConfigurePositionYInertiaModifiers(modifiers);