基于指针的动画

本文介绍如何使用 WinUI 和 Windows 应用 SDK 应用中指针的位置来创建动态的“粘附游标”体验。

先决条件

此处,我们假设你熟悉以下文章中讨论的概念:

为什么创建指针位置驱动的体验?

Fluent 设计语言中,触摸并不是与 UI 交互的唯一方法。 由于 WinUI 应用可以跨越多个设备外形规格,因此最终用户与其他输入形式(如鼠标和触控笔)进行交互。 使用来自这些其他输入形式的位置数据,使最终用户感觉与你的应用更加紧密相连。

通过指针位置驱动体验,可以利用指针输入形式的屏幕位置为应用创建额外的动作和 UI 体验。 这些体验通常可为最终用户提供有关 UI 行为和结构的附加上下文和反馈。 体验不再是单向流,而是变为双向流,用户以其输入方式提供输入,应用 UI 可以响应。

一些示例包括:

  • 聚焦 的位置进行动画处理以跟随光标

    指针聚焦示例

  • 根据指针的位置旋转图像

    指针旋转示例

使用 PointerPositionPropertySet

可以使用 PointerPositionPropertySet 创建这些体验。 为 UIElement 创建此属性集,用于在 UIElement 成功命中测试后保持指针的位置。 位置值是相对于 UIElement 的坐标空间而言的(位置 <0,0> 是 UIElement 的左上角)。 然后,可以利用动画中设置的此属性来驱动另一个属性的运动。

对于每个不同的指针输入形式,有一些输入状态,输入可能位于位置更改的位置:悬停、按下、按下和移动。 PointerPositionPropertySet 仅保持鼠标和笔在悬停、按下以及按下并移动状态下的指针位置。

入门的常规步骤:

  1. 标识希望跟踪指针位置的UIElement。
  2. 通过 ElementCompositionPreview 访问 PointerPositionPropertySet。
  3. 创建一个 ExpressionAnimation,该表达式引用 PropertySet 中的 Position 属性。
    • 不要忘记设置引用参数!
  4. 使用 ExpressionAnimation 定位 CompositionObject 的属性。

注释

建议将 GetPointerPositionPropertySet 方法返回的 PropertySet 分配给类变量。 这可确保垃圾回收机制不会清理属性集合,因此不会对其引用的 ExpressionAnimation 产生任何影响。 ExpressionAnimations 不保持对公式中使用的任何对象的强引用。

示例

让我们看看一个示例,其中我们利用鼠标和笔输入形式的悬停位置动态旋转图像。

指针旋转示例

该图像是 UIElement,因此让我们首先获取对 PointerPositionPropertySet 的引用

_pointerPositionPropSet = ElementCompositionPreview.GetPointerPositionPropertySet(element);

在此示例中,有两个表达式正在发挥作用:

  • 随着指针距离图像中心的变化,图像进行旋转。 距离越远,旋转就越大。
  • 旋转轴根据指针的位置更改的表达式。 希望旋转轴垂直于位置的向量。

在这里,定义两个表达式,一个面向 RotationAngle 属性,另一个面向 RotationAxis 属性。 就像引用其他任何属性集一样引用 PointerPositionPropertySet。

在此示例中,你将使用 ExpressionBuilder 类生成表达式。

// using EF = ExpressionBuilder.ExpressionFunctions;
// || DEFINE THE EXPRESSION FOR THE ROTATION ANGLE ||
var hoverPosition = _pointerPositionPropSet.GetSpecializedReference
<PointerPositionPropertySetReferenceNode>().Position;
var angleExpressionNode =
EF.Conditional(
 hoverPosition == new Vector3(0, 0, 0),
 ExpressionValues.CurrentValue.CreateScalarCurrentValue(),
 35 * ((EF.Clamp(EF.Distance(center, hoverPosition), 0, distanceToCenter) % distanceToCenter) / distanceToCenter));
_tiltVisual.StartAnimation("RotationAngleInDegrees", angleExpressionNode);

// || DEFINE THE EXPRESSION FOR THE ROTATION AXIS ||
var axisAngleExpressionNode = EF.Vector3(
-(hoverPosition.Y - center.Y) * EF.Conditional(hoverPosition.Y == center.Y, 0, 1),
 (hoverPosition.X - center.X) * EF.Conditional(hoverPosition.X == center.X, 0, 1),
 0);
_tiltVisual.StartAnimation("RotationAxis", axisAngleExpressionNode);

另请参阅