本文介绍如何在 WinUI 中使用 Spring NaturalMotionAnimations。
先决条件
此处,我们假设你熟悉以下文章中讨论的概念:
为什么是泉水?
弹簧是一种我们在生活中的某个阶段都经历过的常见动态体验;从弹簧玩具到物理教室里与系在弹簧上的木块的体验。 弹簧的振荡运动经常引起观察者轻松和愉快的情感反应。 因此,弹簧的运动能很好地转化为应用程序 UI,对于那些希望创建更生动、更吸引最终用户的运动体验的人来说,比传统的立方贝塞尔更有表现力。 在这些情况下,春季运动不仅创造了一个活泼的运动体验,而且还有助于引起人们对新内容或当前动画内容的注意。 根据应用程序品牌或运动语言,振荡更为明显,但在其他情况下,振荡更为微妙。
在 UI 中使用弹簧
如前所述,斯普林斯是一个有用的动作,可以集成到 WinUI 应用,以引入非常熟悉和俏皮的 UI 体验。 UI 中弹簧的常见用法包括:
| Spring 使用说明 | 视觉示例 |
|---|---|
| 使动态体验更加“突出”,看起来更生动。 (动画缩放) |
|
| 使运动体验微妙地感觉更精力充沛 (动画偏移) |
|
在这些情况下,可以通过“弹跳到”并在新值附近振荡或在当前值周围以初始速度振荡来触发弹簧运动。
定义弹簧运动
使用 NaturalMotionAnimation API 创建春季体验。 具体而言,使用 Compositor 中的 Create* 方法创建 SpringNaturalMotionAnimation。 然后,可以定义运动的以下属性:
- DampingRatio - 表示动画中弹簧运动的阻尼程度。
| 抑制比率值 | 说明 |
|---|---|
| 阻尼比(DampingRatio)= 0 | 无阻尼 - 弹簧将振荡很长时间 |
| 0 < 阻尼比 < 1 | 欠阻尼的弹簧会从小幅到大幅振荡。 |
| 阻尼比 = 1 | 严重阻尼 - 弹簧不会产生振荡。 |
| DampingRatio > 1 | 过阻尼——弹簧会快速到达目的地,并且由于突然减速而没有振荡。 |
- 周期 – 弹簧完成一次振荡所需的时间。
- Final / Starting Value – 定义弹簧运动的起始值和结束值(如果未定义,起始值和/或最终值将取当前值)。
- 初始速度 - 用编程设置运动的初始速度。
还可以定义与 KeyFrameAnimations 相同的动作的一组属性:
- DelayTime/Delay 行为
- StopBehavior
在常见的对偏移量和缩放/尺寸进行动画处理的情况下,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 属性。
示例
在此示例中,你将创建一个导航和画布的用户界面体验,当用户单击展开按钮时,导航窗格会以弹性振动的动画效果展开。
首先,在单击事件中定义当导航窗格出现时的 spring 动画。 然后,使用 InitialValueExpression 功能定义动画的属性,以使用表达式定义 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);
}
现在,如果想要将此动作绑定到输入,该怎么办? 那么,如果终端用户轻扫,窗格会呈现出弹簧运动? 更重要的是,如果用户用力或快速地滑动,系统会根据用户的滑动速度进行调整。
为此,您可以采用我们的同一 Spring Animation,并将其传递给 InteractionTracker 中的惯性修饰符。 有关 InputAnimations 和 InteractionTracker 的详细信息,请参阅 InteractionTracker 的自定义操作体验。 我们假设在本代码示例中,你已设置 InteractionTracker 和 VisualInteractionSource。 我们将重点创建 InertiaModifiers,它将采用 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 中同时具有程序化和输入驱动的弹簧动画!
总之,在应用中使用春季动画的步骤:
- 在 Compositor 上创建 SpringAnimation。
- 如果需要非默认值,请定义 SpringAnimation 的属性:
- 阻尼比
- 期限
- 最终值
- 初始值
- 初速度
- 分配给对象。
- 如果要对 CompositionObject 属性进行动画处理,请将 SpringAnimation 作为参数传递给 StartAnimation。
- 如果要与输入一起使用,请将 InertiaModifier 的 NaturalMotion 属性设置为 SpringAnimation。