本文介绍如何使用 WinUI 和 Windows 应用 SDK 应用中指针的位置来创建动态的“粘附游标”体验。
先决条件
此处,我们假设你熟悉以下文章中讨论的概念:
为什么创建指针位置驱动的体验?
在 Fluent 设计语言中,触摸并不是与 UI 交互的唯一方法。 由于 WinUI 应用可以跨越多个设备外形规格,因此最终用户与其他输入形式(如鼠标和触控笔)进行交互。 使用来自这些其他输入形式的位置数据,使最终用户感觉与你的应用更加紧密相连。
通过指针位置驱动体验,可以利用指针输入形式的屏幕位置为应用创建额外的动作和 UI 体验。 这些体验通常可为最终用户提供有关 UI 行为和结构的附加上下文和反馈。 体验不再是单向流,而是变为双向流,用户以其输入方式提供输入,应用 UI 可以响应。
一些示例包括:
对 聚焦 的位置进行动画处理以跟随光标
根据指针的位置旋转图像
使用 PointerPositionPropertySet
可以使用 PointerPositionPropertySet 创建这些体验。 为 UIElement 创建此属性集,用于在 UIElement 成功命中测试后保持指针的位置。 位置值是相对于 UIElement 的坐标空间而言的(位置 <0,0> 是 UIElement 的左上角)。 然后,可以利用动画中设置的此属性来驱动另一个属性的运动。
对于每个不同的指针输入形式,有一些输入状态,输入可能位于位置更改的位置:悬停、按下、按下和移动。 PointerPositionPropertySet 仅保持鼠标和笔在悬停、按下以及按下并移动状态下的指针位置。
入门的常规步骤:
- 标识希望跟踪指针位置的UIElement。
- 通过 ElementCompositionPreview 访问 PointerPositionPropertySet。
- 将 UIElement 传递到 ElementCompositionPreview.GetPointerPositionPropertySet 方法。
- 创建一个 ExpressionAnimation,该表达式引用 PropertySet 中的 Position 属性。
- 不要忘记设置引用参数!
- 使用 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);