故事板概述
本概述重点介绍如何在 Windows 动画中使用过渡和故事板。 有关 Windows 动画组件的概述,请参阅 Windows 动画概述。
本主题包含以下各节:
转换
转换定义单个动画变量在特定时间间隔内的变化方式。 Windows 动画包含一个常见转换库,开发人员可应用于一个或多个动画变量。 不同类型的转换具有不同的参数集,其中可能包括转换完成时的变量值、转换持续时间或基础数学函数特有的数量,例如加速或振荡范围。
所有转换共享两个隐式参数:数学函数的初始值和初始速度(斜率)。 这些值可由应用程序显式指定,但通常由动画管理器设置为切换开始时动画变量的值和速度。
转换库
转换库当前提供以下转换。 如果应用程序需要的效果无法使用转换库指定,开发人员可以通过为应用程序实现自定义内插器或使用第三方转换库来创建其他类型的转换。
转换名称 | 说明 |
---|---|
accelerate-decelerate |
动画变量在给定持续时间内先加快速度,然后减慢速度。 |
constant |
动画变量在整个转换过程中保持其初始值。 |
cubic |
动画变量在给定持续时间内以指定的最终速度从其初始值更改为指定的最终值。 |
离散 |
动画变量在指定的延迟时间内保持其初始值,然后瞬时切换到指定的最终值,并在给定的保持时间内保持该值。 |
瞬时 |
动画变量会立即从其当前值更改为指定的最终值。 |
linear |
动画变量在给定持续时间内从其初始值线性转换为指定的最终值。 |
从速度线性 |
动画变量以指定的速度从初始值线性过渡到指定的最终值。 |
加速抛物线 |
动画变量以指定的最终速度从其初始值转换为指定的最终值,并用指定的加速更改其速度。 |
倒转 |
变量在给定持续时间内更改方向。 最终值将与初始值相同,最终速度将是初始速度的负值。 |
正弦从范围 |
变量在给定值范围内振荡,在给定持续时间内具有指定振荡期。 |
正弦从速度 |
变量在给定持续时间内以指定的振荡期振荡。 振荡幅度由变量的初始速度决定。 |
平滑停止 |
动画变量在指定的最终值(最长持续时间内)处平滑停止。 |
下表包含每个转换的插图。
图示 |
---|
自定义过渡
内插器定义数学函数,该函数确定动画变量在从初始值到最终值的过程中如何随时间变化。 转换库中的每个转换都有一个关联的内插器对象,该对象由系统提供并实现内插器函数。 如果应用程序需要的效果无法使用转换库指定,则它可以通过为每个新转换实现一个或内插器对象来实现一个或多个自定义转换。 内插器对象不能由应用程序直接使用,必须改为包装在关联的转换中。 转换工厂用于从内插器对象生成转换。 有关更多详细信息,请参阅 IUIAnimationInterpolator 和 IUIAnimationTransitionFactory。
请注意,大多数应用程序将通过使用转换库获得所需的所有转换,因此不需要实现内插器。
情节提要
故事板是随着时间推移应用于一个或多个动画变量的过渡集合。 故事板中的切换可以保证彼此保持同步,故事板作为一个单元进行计划或取消。 创建所需的过渡后,应用程序使用动画管理器创建故事板,将过渡添加到故事板,适当配置故事板,并安排它尽快播放。 动画管理器确定故事板的实际开始时间,因为当前对相同变量进行动画处理的其他故事板要可能存在争用。
故事板的总体持续时间取决于故事板中切换的持续时间。 转换的持续时间不需要固定;它可以由动画变量在转换开始时的值和速度确定。 因此,故事板的持续时间也可以取决于其动画变量的状态。
以下示例假定已创建动画管理器、转换库和计时器。 有关详细信息,请参阅创建主动画对象。 这些示例还假定应用程序已使用 IUIAnimationManager::CreateAnimationVariable 方法和 5 个转换(T1、T2、T3、T4 和 T5)创建了三个动画变量(X、Y 和 Z),通过使用 IUIAnimationTransitionLibrary 接口的方法之一。
构建简单故事板
若要生成简单的故事板,请使用 IUIAnimationManager::CreateStoryboard 方法创建新的故事板,使用IUIAnimationTransitionLibrary::CreateLinearTransition 方法来创建线性过渡,使用T1 和 IUIAnimationStoryboard::AddTransition 方法将 T1 转换应用到变量 X,并将生成的转换添加到故事板。
此过程生成简单的故事板,如下图所示。 故事板包含一个转换 T1,因此变量 X 的值在固定时间段内线性变化。
请注意,对于此类简单方案,替代选项是使用 IUIAnimationManager::ScheduleTransition 方法。
使用上下文敏感持续时间
虽然某些转换具有固定持续时间,但其他转换的持续时间取决于切换开始时动画变量的初始值或速度。 例如,IUIAnimationTransitionLibrary::CreateLinearTransitionFromSpeed 方法创建一个转换,其持续时间与动画变量的初始值与指定的最终值之间的差异成正比。 在此图示和其余插图中,这种任意持续时间的此类转换都用问号 (?) 表示,并且其实际持续时间在故事版播放时确定。
构建更复杂的故事板
创建故事版并添加单个转换后,T1 可以再次调用 IUIAnimationStoryboard::AddTransition 方法,但使用 T2 而不是 T1 来追加 X 变量的第二个转换。
假设 T2 转换的持续时间与上下文相关,则故事板现在就包含影响变量 X 的任意持续时间的两个回退转换。
使用可变 Y 和切换 T3 再次调用 AddTransition 会在故事板开始时添加第三个转换。 根据情节提要播放时的 X 和 Y 的值,T3 可能在 T1 之后甚至 T2 之后结束。
使用关键帧
若要在故事板开始时的偏移量添加切换效果,必须先添加一个关键帧。 关键帧表示时间上的瞬间,其本身对故事板的行为没有任何影响。 每个故事板都有一个隐式关键帧,表示故事板的开头,UI_ANIMATION_KEYFRAME_STORYBOARD_START;可以通过使用 UI_ANIMATION_KEYFRAME_STORYBOARD_START 调用 IUIAnimationStoryboard::AddKeyframeAtOffset 方法,从头开始添加新的关键帧。
添加关键帧的偏移量始终相对于另一个关键帧。 下图显示了添加关键帧1 和转换 T4 的结果,它应用于变量 Z,与关键帧 1 保持一致,并使用固定持续时间创建。 当然,由于其他转换的持续时间尚不清楚,因此 T4 可能不是最后一次转换完成。
也可以使用 IUIAnimationStoryboard::AddKeyframeAfterTransition 方法将关键帧放置在转换的末尾。 下图显示了在 T1 之后添加关键帧 2 和 T2 之后的关键帧 3 的结果。
由于 T1 和 T2 的持续时间在故事板播放之前未知,因此关键帧 2 和关键帧3 的偏移量也要到那时才能确定。 因此,关键帧 2 甚至关键帧 3 都可能早于关键帧 1 出现。
转换的开始和结束都可以使用 IUIAnimationStoryboard::AddTransitionBetweenKeyframes 方法与关键帧对齐。 下图显示了在关键帧 2 和关键帧 3 之间的变量 Y 上添加第五个转换 T5 的结果。 这会更改 T5 的持续时间,使其更长或更短,具体取决于关键帧 2 和关键帧 3 的相对偏移量。
保存变量
如果 T4 在 T2 和 T5 之后结束,那么故事板将停止对变量 X 和 Y 进行动画处理,使其他故事板可以对它们进行动画制作。 但是,应用程序可以调用 IUIAnimationStoryboard::HoldVariable 方法,请求故事板将其动画的部分或全部变量保持为最终值,直到故事板结束。 下图显示了 T4 最后一次保持 X 和 Z 的结果。 请注意,故事板在其最终值上保存 X,直到故事板结束。 保留对 Z 没有影响,因为故事板在 T4 完成时结束。
尽管 Y 不是由此故事板持有的,但它的值不会在 T5 完成后更改,除非另一个故事板对其进行动画处理。 由于 Y 未被保留,因此任何其他故事板(无论优先级如何)都可以在 T5 完成后对 Y 进行动画处理。 相比之下,由于 X 已被保留,因此在完成该故事版之前,低优先级故事板无法对 X 进行动画处理。
所有这些图示都假定故事板开始播放时变量的任意当前值集。 如果遇到其他值,则上下文敏感转换的持续时间可能有所不同,如下图所示。
在此方案中,T5 在 T3 完成之前开始,因此 T3 会被剪裁。 由于 T4 早于 T2 和 T5 完成,因此 Z 的值将一直保留到故事板末尾。 通常,故事板开始播放时变量的值和速度可能会影响关键帧排序以及故事板的整体长度和形状。
计划故事板
安排故事板时,其开始时间取决于其大纲和当前计划表中故事板的大纲。 具体而言,故事板对每个单独的变量进行动画处理的第一个和最后一刻决定了两个故事板是否以及何时发生碰撞,但其中转换的内部细节并不重要。
下图显示了故事板的轮廓,其中五个过渡对三个变量进行动画处理。
Windows 动画平台的基石是支持在必要时让一个动画在另一个动画开始之前完成。 虽然这消除了许多逻辑问题,但它也会在 UI 中引入任意延迟。 为了解决此问题,应用程序可以使用 IUIAnimationStoryboard::SetLongestAcceptableDelay 方法指定故事板启动时间最长的可接受延迟,动画管理器使用此信息在指定的延迟期过前计划故事板。 安排故事板时,动画管理器确定是否必须先取消、剪裁、结束和/或压缩其他故事板。
应用程序可以注册在故事板的状态更改时调用的处理程序。 这使应用程序能够在故事板开始播放、运行到完成、完全从计划中删除时做出响应,或者由于优先级较高的故事板中断而无法完成。 若要标识传递给故事板处理程序(或优先级比较)的故事板,应用程序可以使用 IUIAnimationStoryboard::SetTag 方法将标记应用于故事板,类似于可用于标识变量的故事板。 与重新使用故事板一样,开发人员在使用标记标识故事板时必须谨慎,并确保在用户操作导致许多故事板排队时不会出现歧义。
以下示例演示了尝试计划本主题前面部分中生成的故事板的两种变体。
在此方案中,有六个情节提要(A 到 F)已计划对变量 W、X、Y 和 Z 进行动画处理,但只有 A 和 B 已开始播放。 标有 G 的新故事板的最长可接受延迟设置为下图所示的持续时间。
应用程序已注册优先级比较,其中包括以下逻辑:
- G 只能取消 C 和 E,并且只为了防止失败。
- G 只能剪裁 A、C、E 和 F,并且只为了防止故障。
- 任何故事板都可以压缩任何其他故事板(始终只执行压缩以防止失败)。
注意
限定符"only to prevent failure"表示仅当 priorityEffect 参数为 UI_ANIMATION_PRIORITY_EFFECT_FAILURE 时,已注册的优先级比较才会返回 S_OK。 有关详细信息,请参阅 IUIAnimationPriorityComparison::HasPriority 方法。
若要在最长可接受的延迟过前启动 G,动画管理器必须执行以下操作:
- 剪裁 F
- 取消 E
取消 E 后,D 和 F 将被揭开并恢复到原始轮廓:
动画管理器无需在 C 的最长可接受延迟结束前取消或调整 C 的计划,因此 C 和 G 的会合决定了 G 的启动时间。
成功安排 G 后,可以确定其转换的持续时间,因此可以确定其大纲的其余部分。 但是,如果随后从计划中删除另一个故事板,大纲可能会更改。
作为第二个示例,请考虑上述方案,但为 G 指定的最长可接受延迟时间较短。
在这种情况下,将采取以下措施:
- 剪裁 F
- 取消 E
- 取消 C
此外,动画管理器必须按显示的量压缩 D,以使 G 在最长的可接受延迟后启动,而不能再晚。
为了保留其相对计时,也会压缩 A、B 和 F。
但是,不会压缩不相关的变量(未显示)的故事板。
同样,G 的大纲现在已知,并且与第一个方案中的结果不同,因为当 G 开始时,变量具有不同的值。