在本文中,我们将更深入地探讨如何利用互动追踪器的 InertiaModifier 功能特性来创造运动体验,使其与 WinUI 应用程序中指定的点对齐。
在 WinUI 应用中, InteractionTracker 相关的惯性修饰符类型位于命名空间中 Microsoft.UI.Composition.Interactions 。
先决条件
此处,我们假设你熟悉以下文章中讨论的概念:
什么是吸附点,为什么它们很有用?
在构建自定义操作体验时,有时创建一些专门设计的位置点在可滚动/可缩放画布中会很有帮助,这些位置点是 InteractionTracker 在结束滚动或缩放时总会停留的地方。 这些通常称为 捕捉点。
请注意,在以下示例中,滚动如何将 UI 停留在不同图像之间的不自然位置。
如果添加吸附点,在停止滚动时,图像会吸附到指定的位置。 借助吸附点,它使滚动浏览图像的体验更加流畅且响应更快。
InteractionTracker 和 InertiaModifiers
使用 InteractionTracker 创建自定义操作体验时,可以通过利用 InertiaModifiers 来创建贴靠点运动体验。 惯性修饰器本质上是一种方法,用于定义 InteractionTracker 在进入惯性状态时到达目的地的位置或方式。 可以应用 InertiaModifiers 来影响 InteractionTracker 的 X 或 Y 位置或者缩放属性。
有三种惯性修饰符类型:
- InteractionTrackerInertiaRestingValue – 一种修改交互或程序化速度之后的最终静止位置的方法。 预定义的动作会将 InteractionTracker 带到该位置。
- InteractionTrackerInertiaMotion – 定义特定动作 InteractionTracker 的方法将在交互或编程速度后执行。 最终位置将从此运动生成。
- InteractionTrackerInertiaNaturalMotion – 在交互或编程速度之后定义最终休息位置的方法,但具有基于物理的动画(NaturalMotionAnimation)。
进入惯性时,InteractionTracker 会评估每个分配给它的惯性修正器,并确定它们是否适用。 这意味着你可以创建多个 InertiaModifiers 并将其分配给 InteractionTracker。 但是,在定义每个项时,需要执行以下操作:
- 定义条件 – 一个表达式,用于定义何时应应用此特定的 InertiaModifier。 这通常需要查看 InteractionTracker 的 NaturalRestingPosition(默认惯性下的目标位置)。
- 定义 RestingValue/运动/自然运动 – 在满足条件时,定义实际的静止值表达式、运动表达式或自然运动动画。
注释
当 InteractionTracker 进入惯性时,惯性修饰符的条件部分仅会被评估一次。 但是,仅对于 InertiaMotion,只有在修饰符条件为 true 的情况下,运动表达式才会在每一帧被计算。
示例
现在让我们看看如何使用 InertiaModifiers 创建一些吸附点体验来重新创建图像滚动画布。 在此示例中,每个操作都旨在潜在移动单个图像,这通常称为“单一必需对齐点”。
首先,设置交互跟踪器 (InteractionTracker)、视觉交互源 (VisualInteractionSource) 和利用交互跟踪器位置的表达式。
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);
此关系图提供正在发生的逻辑的直观描述:
现在,您只需为每个 InertiaModifier 定义静止值:将 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 进入其惯性状态时,它将检查惯性修饰符的条件,以确定其位置是否应修改。
var modifiers = new InteractionTrackerInertiaRestingValue[] {
snapUpModifier, snapDownModifier };
_tracker.ConfigurePositionYInertiaModifiers(modifiers);