情节提要动画不仅限于视觉动画。 通过故事板创建的动画是将依赖属性值按照时间变化的方法。 之所以可能需要一个不在动画库中的情节提要动画,主要原因之一是为了定义控件的视觉状态,使其成为控件模板或页面定义的一部分。
定义情节提要动画
使用故事板的动画是一种将依赖属性的值随时间变化的方法。 您正在设置动画的属性不一定都是直接影响您应用 UI 的属性。 但是,由于 XAML 是用于定义应用程序的 UI,通常你会对与 UI 相关的属性进行动画效果。 例如,可以对 RotateTransform 的角度或按钮背景的颜色值进行动画处理。
定义情节提要动画的一个主要原因是,如果你是一个控件的作者,或者你正在为控件重新设计模板,并在定义其视觉状态。 有关详细信息,请参阅视觉状态的情节提要动画。
无论是为应用定义视觉状态还是自定义动画,本主题中介绍的情节提要动画的概念和 API 主要适用于这两者。
为了进行动画处理,你以情节提要动画为目标的属性必须是 依赖属性。 依赖属性是 Windows 运行时 XAML 实现的关键功能。 最常见的 UI 元素的可写属性通常作为依赖属性实现,以便可以对其进行动画处理、应用数据绑定值,或者应用 Style 并使用 Setter 定位属性。 有关依赖属性的工作原理的详细信息,请参阅 依赖项属性概述。
大多数情况下,通过编写 XAML 来定义情节提要动画。 如果使用 Microsoft Visual Studio 之类的工具,它将为你生成 XAML。 也可以使用代码定义情节提要动画,但这不太常见。
让我们看一个简单的示例。 在此 XAML 示例中, Opacity 属性在特定的 Rectangle 对象上进行动画处理。
<Page ...>
<Page.Resources>
<!-- Storyboard resource: Animates a rectangle's opacity. -->
<Storyboard x:Name="myStoryboard">
<DoubleAnimation
Storyboard.TargetName="MyAnimatedRectangle"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:1"/>
</Storyboard>
</Page.Resources>
<!--Page root element, UI definition-->
<Grid>
<Rectangle x:Name="MyAnimatedRectangle"
Width="300" Height="200" Fill="Blue"/>
</Grid>
</Page>
标识要进行动画处理的对象
在前面的示例中,动画板正在对矩形的不透明度属性进行动画化。 你不会在对象本身上声明动画。 而是在故事板的动画定义中执行此操作。 情节板通常在 XAML 中定义,而不是在需要动画处理的对象的 XAML UI 定义的直接附近。 相反,它们通常配置为 XAML 类型的资源。
若要将动画连接到目标,可以通过其标识编程名称来引用目标。 应始终在 XAML UI 定义中应用 x:Name 属性 来命名要进行动画处理的对象。 然后,通过在动画定义中设置 Storyboard.TargetName ,将对象定位为动画。 对于 Storyboard.TargetName 的值,请使用目标对象的名称字符串,即前面和其他地方使用 x:Name 属性设置的名称字符串。
以依赖属性为目标进行动画处理
在动画中为 Storyboard.TargetProperty 设置值。 这将决定目标对象的哪个特定属性会被动画化。
有时,你需要定位一个属性,这个属性不是目标对象的直接属性,而是嵌套在对象-属性关系中的较深层的属性。 通常需要执行此操作以深入探索一组参与对象和属性值,直到可以引用可动画的属性类型(Double、Point、Color)。 此概念称为 间接目标,以这种方式定位属性的语法称为 属性路径。
下面是一个示例。 故事板动画的一个常见场景是更改应用 UI 或控件的一部分的颜色,以表示控件处于特定状态。 假设你想要对 TextBlock的前景进行动画处理,使其从红色变为绿色。 你可能会认为 会涉及 ColorAnimation ,这确实是正确的。 但是,影响对象的颜色的 UI 元素上的属性实际上都不是 Color 类型。 而是 Brush 类型。 因此,你实际需要面向动画的是 Color 属性,该属性属于 SolidColorBrush 类,这是一种 Brush 派生的类型,通常用于这些颜色相关的 UI 属性。 以下是关于为动画的属性目标构建属性路径的示例:
<Storyboard x:Name="myStoryboard">
<ColorAnimation
Storyboard.TargetName="tb1"
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
From="Red" To="Green"/>
</Storyboard>
下面介绍如何从其部分考虑此语法:
- 每个 () 括号括起一个属性名称。
- 在属性名称中,有一个点,该点分隔类型名称和属性名称,以便标识的属性明确。
- 中间的那个点(不在括号内)表示一个步骤。 这通过语法解释为,获取第一个属性(这是一个对象)的值,进入其对象模型,并定位第一个属性值的特定子属性。
下面是一个动画定位场景列表,其中你可能会使用间接属性定位,以及一些近似你所用语法的属性路径字符串。
- 对 TranslateTransform 的 X 值进行动画处理,如应用于 RenderTransform:
(UIElement.RenderTransform).(TranslateTransform.X) - 对 LinearGradientBrush 的 GradientStop 内的颜色进行动画处理,应用于填充:
(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color) - 对 TranslateTransform 的 X 值进行动画处理,该值是 TransformGroup 中 4 个转换中的 1 个,应用于 RenderTransform:
(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)
你会注意到其中一些示例使用方括号括在数字周围。 这是一个索引器。 它表明其前面的属性名称是一个集合的值,并且您希望从该集合中获取一个由从零开始的索引标识的项目。
还可以对 XAML 附加属性进行动画处理。 例如, (Canvas.Left)始终将完整的附加属性名称括在括号中。 有关详细信息,请参阅 对 XAML 附加属性进行动画处理。
有关如何使用属性路径间接定位要进行动画处理的属性的更多信息,请参阅 Property-path 语法。
动画类型
Windows 运行时动画系统有三种特定类型,故事板动画可以应用于:
- Double,可以使用任何 DoubleAnimation 进行动画处理
- 点,可以使用任何 PointAnimation 进行动画处理
- 颜色,可以使用任何 ColorAnimation 进行动画
还有对象引用值的通用 对象 动画类型,稍后我们将讨论这些类型。
指定动画值
到目前为止,我们演示了如何指定对象和属性进行动画处理,但尚未说明动画在运行时对属性值的影响。
我们介绍的动画类型有时称为 “从/到/By ”动画。 这意味着动画使用来自动画定义的一个或多个输入来更改属性的值,随着时间的推移:
- 该值从 From 值开始。 如果未指定 From 值,则起始值是动画运行之前动画属性具有的任何值。 这可能是默认值、样式或模板中的值,或者 XAML UI 定义或应用代码专门应用的值。
- 动画结束时,值为 To。
- 或者,若要指定相对于起始值的结束值,请设置 By 属性。 应设置此属性,而不是 To 属性。
- 如果未指定 To 值或 By 值,则结束值是动画运行前属性具有的任何值。 在这种情况下,最好有 From 值,因为否则动画根本不会更改值;其起始值和结束值都是相同的。
- 动画通常至少有一个From、By或To,但从不全部同时具备。
让我们重新访问前面的 XAML 示例,并再次查看 From 和 To 值以及 Duration。 该示例对 Opacity 属性进行动画处理, 而 Opacity 的属性类型为 Double。 因此,此处要使用的动画是 DoubleAnimation。
From="1.0" To="0.0" 指定动画运行时, Opacity 属性从值 1 开始,并将动画设置为 0。 换句话说,就这些 Double 值对 Opacity 属性的含义而言,此动画将导致对象开始不透明,然后淡入透明状态。
...
<Storyboard x:Name="myStoryboard">
<DoubleAnimation
Storyboard.TargetName="MyAnimatedRectangle"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:1"/>
</Storyboard>
...
Duration="0:0:1" 指定动画持续多长时间,即矩形的淡出速度。
Duration 属性以小时:分钟:秒的形式指定。 此示例中的持续时间为一秒。
有关 Duration 值和 XAML 语法的详细信息,请参阅 Duration。
注释
对于我们展示的示例,如果您确定正在进行动画处理的对象,其初始状态的不透明度始终等于1(无论是通过默认设置还是明确设置),您可以省略From值,此时动画将使用默认的起始值,结果将保持不变。
From/To/By 可为 null
我们之前提到,你可以省略 From、 To 或 By ,从而使用当前非动画值作为缺失值的替代。 动画的 From、 To 或 By 属性不是你可能猜到的类型。 例如, DoubleAnimation.To 属性的类型不是 Double。 对于Double,它是可为null。 其默认值为 null,而不是 0。 动画系统通过 null 值来区分您未为 From、To 或 By 属性专门设置值。
动画的其他属性
本节中所述的下一个属性都是可选的,因为它们具有适用于大多数动画的默认值。
AutoReverse
如果未在动画上指定 AutoReverse 或 RepeatBehavior ,该动画将运行一次,并在指定为 Duration 的时间运行。
AutoReverse 属性指定时间线在到达播放持续时间末尾时是否反向播放。 如果将其设置为 true,则动画在达到其声明的 Duration 末尾后会反转,将值从其结束值(To)更改为其起始值(From)。 这意味着动画的有效运行时间是其原始持续时间的两倍。
RepeatBehavior
RepeatBehavior 属性用于指定时间线播放的次数,或者时间线应重复的最大持续时间。 默认情况下,时间线的迭代计数为“1x”,这意味着它在 持续时间 内播放一次,并且不会重复。
您可以使动画运行多次迭代。 例如,值为“3x”会导致动画运行三次。 或者,可以为 RepeatBehavior 指定不同的持续时间。 该 持续时间 应比动画本身的 持续时间 长,才能生效。 例如,如果您为持续时间为“0:0:2”的动画指定 RepeatBehavior 为“0:0:10”,则该动画将重复五次。 如果这些不均匀划分,则在达到 RepeatBehavior 时间时,动画将被截断,这可能正在进行中。 最后,可以指定特殊值“永远”,这会导致动画无限运行,直到它故意停止。
有关 RepeatBehavior 值和 XAML 语法的详细信息,请参阅 RepeatBehavior。
FillBehavior=“Stop”
默认情况下,当动画结束时,即使超过其持续时间,动画也仍将属性值保持为最终的 To 值或 By 修改过的值。 但是,如果将 FillBehavior 属性的值设置为 FillBehavior.Stop,则动画值的值将还原到应用动画之前的值,或者更准确地还原到依赖属性系统确定的当前有效值(有关此区别的详细信息,请参阅依赖属性概述)。
BeginTime
默认情况下,动画的 BeginTime 为“0:0:0”,因此它一旦包含 情节提要 运行,就会立即开始。 如果 情节提要 包含多个动画,并且希望将其他动画的开始时间与初始动画交错,或者创建有意的短延迟,则可以更改此值。
SpeedRatio
如果在Storyboard中有多个动画,您可以更改一个或多个动画相对于Storyboard的时间速率。 父 Storyboard 最终控制动画运行时,持续时间 的时间是如何流逝的。 此属性不经常使用。 有关详细信息,请参阅 SpeedRatio。
在情节提要中定义多个动画
情节提要的内容可以是多个动画定义。 如果将相关动画应用于同一目标对象的两个属性,则可能有多个动画。 例如,可以同时更改 TranslateTransform 的 TranslateX 和 TranslateY 属性,该属性用作 UI 元素的 RenderTransform;这将导致元素对角转换。 你需要两个不同的动画来完成此作,但你可能希望动画是同一 情节提要 的一部分,因为你总是希望这两个动画一起运行。
动画不必是同一类型,也不必面向同一对象。 它们可以具有不同的持续时间,无需共享任何属性值。
当父 Storyboard 运行时,内部的每个动画也会运行。
Storyboard 类实际上具有与动画类型相同的许多动画属性,因为两者都共享时间线基类。 因此, Storyboard 可以有 RepeatBehavior 或 BeginTime。 不过,除非希望所有包含的动画具有该行为,否则通常不会在 情节提要 上设置这些动画。 一般情况下,情节提要上设置的任何 Timeline 属性都适用于所有子动画。 如果未设置,Storyboard 的隐式持续时间是通过包含动画的最长持续时间值计算得出的。 在情节草图上显式设置的持续时间如果比其子动画之一短,将导致该动画被截断,这通常是不理想的。
情节板不能包含两个动画,这些动画尝试针对同一个对象并动画同一个属性。 如果尝试这样做,当故事板运行时,会出现运行时错误。 即使由于有意设置不同的BeginTime值和持续时间,使动画在时间上不会重叠,此限制也适用。 如果真的想要将更复杂的动画时间线应用于单个故事板中的同一属性,可以通过以下方法来实现:使用关键帧动画。 请参阅 关键帧和缓动函数动画。
如果这些输入来自多个故事板,动画系统可以将多个动画应用于属性的值。 故意将此行为用于同时运行动画板的情况并不常见。 但是,应用于控件属性的应用定义动画可能会修改以前作为控件视觉状态模型的一部分运行的动画的 HoldEnd 值。
将故事板定义为资源
情节板是在其中放置动画对象的容器。 通常,在页面级资源或 Application.Resources 中,将 Storyboard 定义为可供要进行动画处理的对象的资源。
下一个示例演示如何将上一个示例 情节提要 包含在页面级 资源 定义中,其中 情节提要 是根 页的键式资源。 记下 x:Name 属性。 此属性是定义 Storyboard 的变量名称的方式,以便 XAML 中的其他元素以及代码稍后可以引用 Storyboard 。
<Page ...>
<Page.Resources>
<!-- Storyboard resource: Animates a rectangle's opacity. -->
<Storyboard x:Name="myStoryboard">
<DoubleAnimation
Storyboard.TargetName="MyAnimatedRectangle"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:1"/>
</Storyboard>
</Page.Resources>
<!--Page root element, UI definition-->
<Grid>
<Rectangle x:Name="MyAnimatedRectangle"
Width="300" Height="200" Fill="Blue"/>
</Grid>
</Page>
在 XAML 文件的 XAML 根元素中定义资源(例如 page.xaml 或 app.xaml)是一种常见做法,用于在 XAML 中组织键控资源。 还可以将资源分解为单独的文件,并将其合并到应用或页面中。 有关详细信息,请参阅 ResourceDictionary 和 XAML 资源引用。
注释
Windows 运行时 XAML 支持使用 x:Key 属性 或 x:Name 属性标识资源。 对于 Storyboard,使用 x:Name 属性更为常见,因为最终需要按变量名称引用它,以便可以调用其 Begin 方法并运行动画。 如果使用 x:Key 属性,则需要使用 ResourceDictionary 方法(如 Item 索引器)将其检索为键化资源,然后将检索到的对象强制转换为 Storyboard以使用 Storyboard 方法。
视觉状态的情节提要
当你为控件的视觉外观声明视觉状态动画时,还可以将动画放在 Storyboard 单元中。 在这种情况下,您定义的 Storyboard 元素将进入一个更深嵌套在 样式 中的 VisualState 容器中(这个 样式 是键式资源)。 在这种情况下,不需要为Storyboard指定键或名称,因为VisualState具有VisualStateManager可以调用的目标名称。 控件的样式通常分为单独的 XAML ResourceDictionary 文件,而不是放置在页面或应用 Resources 集合中。 有关详细信息,请参阅视觉状态的情节提要动画。
关联动画和独立动画
此时,我们需要介绍一些关于动画系统工作原理的要点。 具体而言,动画从根本上与 Windows 运行时应用呈现到屏幕的方式以及该呈现如何使用处理线程进行交互。 Windows 运行时应用始终具有主 UI 线程,此线程负责使用当前信息更新屏幕。 此外,Windows 运行时应用还有一个组合线程,该线程用于在显示布局之前立即预先计算布局。 对 UI 进行动画处理时,可能会对 UI 线程造成大量工作。 系统必须在每次刷新之间使用相当短的时间间隔重新绘制屏幕的大区域。 这是为了捕获动画属性的最新值而必须做的。 如果你不小心,动画可能会降低 UI 的响应能力,或者会影响同样在同一 UI 线程上的其他应用功能的性能。
确定降低 UI 线程速度有一定风险的动画种类称为 依赖动画。 不受此风险约束的动画是 独立的动画。 如前面所述,依赖动画和独立动画之间的区别不仅仅是由动画类型(DoubleAnimation 等)决定。 而是根据要进行动画处理的特定属性以及控件的继承和构成等其他因素来确定。 在某些情况下,即使动画确实更改了 UI,动画也会对 UI 线程产生最小影响,而是由合成线程作为独立动画进行处理。
如果动画具有以下任何特征,则动画是独立的:
- 动画的 持续时间 为 0 秒(请参阅警告)
- 动画针对 UIElement.Opacity
- 动画针对这些 UIElement 属性的子属性值:Transform3D、RenderTransform、Projection、Clip
- 动画目标为 Canvas.Left 或 Canvas.Top
- 动画的目标是画笔值,并使用SolidColorBrush,对其Color进行动画处理。
- 动画是 ObjectAnimationUsingKeyFrames
警告
为了使动画被视为独立动画,必须显式设置 Duration="0"。 例如,如果从此 XAML 中删除 Duration="0" ,则动画被视为依赖动画,即使帧的 KeyTime 为“0:0:0”。
<Storyboard>
<DoubleAnimationUsingKeyFrames
Duration="0"
Storyboard.TargetName="Button2"
Storyboard.TargetProperty="Width">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="200"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
如果动画不符合这些条件,则可能是依赖动画。 默认情况下,动画系统不会运行依赖动画。 因此,在开发和测试过程中,甚至可能看不到动画正在运行。 你仍然可以使用此动画,但必须专门启用每个此类依赖动画。 若要启用动画,请将动画对象的 EnableDependentAnimation 属性设置为 true。 (每个表示动画的 Timeline 子类都具有不同的属性实现,但它们都命名 EnableDependentAnimation为 .)
启用依赖动画的责任落在应用开发人员身上,这是动画系统和开发体验中一个经过深思熟虑的设计方面。 我们希望开发人员注意,动画对于 UI 的响应能力确实具有性能成本。 性能不佳的动画很难在全规模应用中隔离和调试。 因此,最好只开启那些对应用程序的 UI 使用体验至关重要的依赖动画。 由于装饰动画使用大量周期,我们不想让你的应用性能受到过于轻易的影响。 有关动画性能提示的详细信息,请参阅 优化动画和媒体。
作为应用开发人员,您还可以选择应用一个全局设置,以始终禁用依赖动画,即使 EnableDependentAnimation 设置为 true 时亦如此。 请参阅 Timeline.AllowDependentAnimations。
小窍门
如果在 Blend for Visual Studio 2019 中使用动画窗格,每当尝试将依赖动画应用于视觉状态属性时,设计器中将显示警告。 生成输出或错误列表中不会显示警告。 如果要手动编辑 XAML,设计器将不会显示警告。 调试时,“输出”窗格的“调试”输出将在运行时显示一条警告,指出动画不独立,并且将被跳过。
启动和控制动画
到目前为止,我们向你展示的所有内容实际上并不会导致动画运行或应用! 在动画启动并运行之前,动画在 XAML 中声明的值变化是潜在的,尚不会发生。 必须以与应用生存期或用户体验相关的某种方式显式启动动画。 在最简单的级别,通过在情节提要上调用作为该动画的父级的 Begin 方法来启动动画。 不能直接从 XAML 调用方法,因此,无论您做什么来启用动画,您将通过代码来实现。 这可以是您应用的页面或组件的后台代码,或者如果您要定义自定义控件类,则可能是控件的逻辑。
通常,你将调用 Begin ,只需让动画运行到其持续时间完成。 但是,还可以使用 “暂停”、“ 恢复 ”和 “停止 ”方法在运行时控制 情节提要 ,以及用于更高级的动画控制方案的其他 API。
在包含无限重复的动画的情节提要上调用 Begin 时,RepeatBehavior="Forever"该动画将运行,直到包含该动画的页面被卸载,或者你专门调用 “暂停 ”或 “停止”。
从应用代码启动动画
可以自动启动动画,或者响应用户操作。 对于自动情况,通常使用对象生存期事件(如 Loaded )充当动画触发器。 加载事件是一个很好的事件,可用于此事件,因为此时 UI 已准备好交互,并且动画不会在开始时被切断,因为 UI 的另一部分仍在加载。
在此示例中, PointerPressed 事件附加到矩形,以便在用户单击矩形时开始动画。
<Rectangle PointerPressed="Rectangle_Tapped"
x:Name="MyAnimatedRectangle"
Width="300" Height="200" Fill="Blue"/>
事件处理程序使用 Storyboard 的 Begin 方法启动 Storyboard(动画)。
myStoryboard.Begin();
myStoryboard().Begin();
如果希望动画完成应用值后运行其他逻辑,则可以处理 已完成 事件。 此外,对于属性系统/动画交互的故障排除, GetAnimationBaseValue 方法非常有用。
小窍门
每当你正在为应用方案编码时,你从应用代码启动动画时,可能需要再次查看 UI 方案的动画库中是否存在动画或过渡。 库动画可在所有 Windows 运行时应用中实现更一致的 UI 体验,并且更易于使用。
视觉状态的动画
用于定义控件视觉状态的 Storyboard 的运行行为与应用直接运行情节提要的方式不同。 应用于 XAML 中的视觉状态定义时, Storyboard 是一个包含 VisualState 的元素,整个状态通过使用 VisualStateManager API 进行控制。 当控件使用包含的 VisualState 时,内部的任何动画都将根据其动画值和时间线属性运行。 有关详细信息,请参阅 视觉状态的情节提要。 对于可视状态,FillBehavior 显示不同。 如果视觉状态更改为另一种状态,则以前的视觉状态及其动画应用的所有属性更改都会被取消,即使新的视觉状态未专门将新动画应用于属性。
情节提要 和 EventTrigger
有一种方法可以启动可在 XAML 中完全声明的动画。 但是,此技术不再广泛使用。 它是 WPF 和 Silverlight 早期版本在支持 VisualStateManager 之前的旧语法。 由于导入/兼容性原因,此 EventTrigger 语法仍适用于 Windows 运行时 XAML,但仅适用于基于 FrameworkElement.Loaded 事件的触发器行为;尝试触发其他事件将引发异常或无法编译。 有关详细信息,请参阅 EventTrigger 或 BeginStoryboard。
对 XAML 附加属性进行动画处理
这不是一种常见方案,但可以将动画值应用于 XAML 附加属性。 有关附加属性及其工作原理的详细信息,请参阅 附加属性概述。 面向附加属性需要一个 属性路径语法 ,该语法将属性名称括在括号中。 可以使用应用离散整数值的 ObjectAnimationUsingKeyFrames 对内置附加属性(如 Canvas.ZIndex)进行动画处理。 但是,Windows 运行时 XAML 实现的现有限制是无法对自定义附加属性进行动画处理。
更多的动画类型,以及学习 UI 动画的下一步
到目前为止,我们演示了在两个值之间进行动画处理的自定义动画,然后在动画运行时根据需要线性内插值。 这些动画称为 From/To/By 动画。 但是,还有一种动画类型,可用于声明介于开始和结束之间的中间值。 这些动画称为 关键帧动画。 还有一种方法可以更改 From/To/By 动画或关键帧动画上的内插逻辑。 这涉及到应用缓动函数。 有关这些概念的详细信息,请参阅 关键帧和缓动函数动画。
与 WPF 的差异
如果你熟悉 Windows Presentation Foundation (WPF),请阅读本部分;否则,可以跳过它。
通常,在 Windows 运行时应用中创建分镜动画类似于 WPF。 但存在一些重要差异:
- 情节提要动画并不是直观地对 UI 进行动画处理的唯一方法,也不一定是应用开发人员执行此作的最简单方法。 与其使用情节提要动画,不如采用主题动画和过渡动画,它们是更好的设计实践。 这些工具可以快速创建推荐的 UI 动画,而无需深入研究动画属性的复杂情况。 有关详细信息,请参阅 XAML 中的动画。
- 在 Windows 运行时中,许多 XAML 控件包括主题动画和过渡动画,作为其内置行为的一部分。 在大多数情况下,WPF 控件没有默认动画行为。
- 如果动画系统确定动画可能会导致 UI 中的性能不佳,则你创建的所有自定义动画都不能默认在 Windows 运行时应用中运行。 系统确定可能存在性能影响的 动画称为依赖动画。 这是一种依赖关系,因为动画的计时直接影响到 UI 线程,而活动用户输入和其他更新也在尝试在这个线程上应用运行时更改。 在 UI 线程上消耗大量系统资源的依赖动画在某些情况下可能会使应用显得无响应。 如果动画导致布局更改,否则可能会影响 UI 线程的性能,则通常需要显式启用动画以查看其运行。 这就是特定动画类的 EnableDependentAnimation 属性的用途。 有关详细信息 ,请参阅从属动画和独立动画 。
- Windows 运行时目前不支持自定义缓动函数。