第 22 章摘要。 动画
注意
本书于 2016 年春季出版,之后再未更新。 书中有许多内容仍然有价值,但有些内容已过时,有些主题不再完全正确或完整。
你已经知道可以使用 Xamarin.Forms 计时器或 Task.Delay
创建自己的动画,但使用 Xamarin.Forms 提供的动画工具通常更容易。 有三个类可以实现这些动画:
ViewExtensions
(高级方法)Animation
(更通用,但较难)AnimationExtension
(最常用、最基础的方法)
通常,动画以可绑定属性支持的属性为目标。 这不是必需的,但这些是对更改做出动态反应的唯一属性。
这些动画没有 XAML 接口,但可以使用第 23 章触发器和行为中进行介绍。
探索基本动画
基本动画功能是 ViewExtensions
类中的扩展方法。 这些方法适用于派生自 VisualElement
的任何对象。 此类最简单的动画以 Chapter 21. Transforms
中讨论的转换属性为目标。
AnimationTryout 演示了 Button
的 Clicked
事件处理程序如何调用 RotateTo
扩展方法以将按钮旋转一周。
RotateTo
方法在四分之一秒的时间内(默认情况下)将 Button
的 Rotation
属性从 0 更改为 360。 但是,如果再次点击 Button
,则不会执行任何操作,因为 Rotation
属性已经是 360 度。
设置动画持续时间
RotateTo
的第二个自变量是持续时间(毫秒)。 如果设置为较大的值,则在动画演示过程中点击 Button
将以当前角度开始一个新的动画。
相对动画
RelRotateTo
方法通过将指定的值添加到现有值来执行相对旋转。 此方法允许多次点击 Button
,每次 Rotation
属性增加 360 度。
等待动画
ViewExtensions
中的所有动画方法都返回 Task<bool>
对象。 这意味着可以使用 ContinueWith
或 await
来定义一系列连续动画。 如果动画在没有中断的情况下完成,则 bool
完成返回值为 false
如果通过 CancelAnimation
方法(该方法将取消在同一元素上设置的 ViewExtensions
中的其他方法启动的所有动画)取消了该动画,返回值则为 true
。
合成动画
可以混合等待和非等待的动画来创建复合动画。 这些是 ViewExtensions
中面向 TranslationX
、TranslationY
和 Scale
转换属性的动画:
请注意,TranslateTo
可能会影响 TranslationX
和 TranslationY
的属性。
Task.WhenAll 和 Task.WhenAny
还可以使用 Task.WhenAll
(在多个任务都结束时发出信号)和 Task.WhenAny
(在多个任务中的第一个任务结束后发出信号)来管理同步动画。
旋转和定位点
调用 ScaleTo
、RelScaleTo
、RotateTo
和 RelRotateTo
方法时,可以将 AnchorX
和 AnchorY
属性设置为指示缩放和旋转的中心。
CircleButton 通过围绕页面中心旋转 Button
来演示此技术。
缓动函数
通常,动画从开始值到结束值都是线性的。 缓动函数会导致动画在整个演示过程中加速或减速。 动画方法的最后一个可选自变量为 Easing
类型,该类定义了 11 个 Easing
类型的静态只读字段:
Linear
(默认值)SinIn
、SinOut
和SinInOut
CubicIn
、CubicOut
和CubicInOut
BounceIn
和BounceOut
SpringIn
和SpringOut
In
后缀表示该效果位于动画的开头,Out
表示该效果位于结尾,InOut
表示该效果位于动画的开头和结尾。
BounceButton 示例演示了如何使用缓动函数。
自己的缓动函数
还可以通过将 Func<double, double>
传递到 Easing
构造函数来定义自己的缓动函数。 Easing
还定义了从 Func<double, double>
到 Easing
的隐式转换。 缓动函数的自变量始终处于 0 到 1 的范围内,因为动画会从头到尾以线性方式演示。 函数通常返回介于 0 到 1 之间的值,但可能短暂地为负值或大于 1(与 SpringIn
和 SpringOut
函数的情况相似),或者,如果你很清楚当前执行的操作,则可能不会遵循该规则。
UneasyScale 示例演示了一个自定义缓动函数,CustomCubicEase 演示了另一个函数。
SwingButton 示例也演示了一个自定义缓动函数,还演示了在一系列旋转动画中更改 AnchorX
和 AnchorY
属性的方法。
Xamarin.FormsBook.Toolkit 库具有 JiggleButton
类,该类使用自定义缓动函数使按钮在单击时抖动. JiggleButtonDemo 示例对此进行了演示。
进入动画
一种常见的动画类型,在页面第一次显示时出现。 此类动画可以在页面的 OnAppearing
重写中启动。 对于这些动画,最佳做法是针对动画后所需的页面显示方式设置 XAML,然后通过代码初始化布局并对其进行动画处理。
FadingEntrance 示例使用 FadeTo
扩展方法淡入页面内容。
SlidingEntrance 示例使用 TranslateTo
扩展方法从侧面滑入页面内容。
SwingingEntrance 示例使用 RotateYTo
扩展方法对 RotationY
属性进行动画处理。 还可使用 RotateXTo
方法。
永久动画
“永久”动画是另一种极端情况,会一直运行到程序终止为止。 此类动画通常供演示之用。
FadingTextAnimation 示例使用 FadeTo
动画淡入和淡出两段文本。
PalindromeAnimation 显示回文,然后按顺序将各个字母旋转 180 度,使它们全部上下颠倒。 然后,整个字符串将翻转 180 度,以读取与原始字符串相同的字符串。
CopterAnimation 示例将旋转出一个简单的 BoxView
直升机形状,同时围绕屏幕中心旋转。
RotatingSpokes 使 BoxView
轮辐围绕屏幕中心旋转,然后旋转每个轮辐本身以创建有趣的图案:
但是,如 RotationBreakdown 示例中所示,从长远来看,逐渐增加元素的 Rotation
属性可能不起作用。
SpinningImage 示例使用 RotateTo
、RotateXTo
和 RotateYTo
使其看起来像是在 3D 空间中旋转位图。
对 bounds 属性进行动画处理
ViewExtensions
中尚未演示的唯一扩展方法是 LayoutTo
,该方法通过调用 Layout
方法有效地对只读 Bounds
属性进行动画处理。 此方法通常由 Layout
派生项调用,将在第 26 章 CustomLayouts 中进行讨论。
LayoutTo
方法应仅限于特殊用途。 BouncingBox 程序在 BoxView
从页面侧面反弹时使用该方法对其进行压缩和展开。
XamagonXuzzle 示例使用 LayoutTo
在经典的 15-16 拼图的实现中移动磁贴,该拼图显示杂乱的图像而不是编号磁贴:
自己的可等待动画
TryAwaitableAnimation 示例创建可等待动画。 在动画完成时,可以从方法返回 Task
对象并发出信号的关键类是 TaskCompletionSource
。
深入了解动画
Xamarin.Forms 动画系统可能会有些混乱。 除了 Easing
类,该动画系统还包括 ViewExtensions
、Animation
和 AnimationExtension
类。
ViewExtensions 类
你已经了解了 ViewExtensions
。 它定义了九种方法,这些方法返回 Task<bool>
和 CancelAnimations
。 9 个方法中的 7 个方法以转换属性为目标。 另外两个是 FadeTo
(以 Opacity
属性为目标)和 LayoutTo
(调用Layout
方法)。
Animation 类
Animation
类具有构造函数,该构造函数具有五个用于定义回调和完成方法的自变量以及动画参数。
可以通过 Add
、Insert
、WithConcurrent
和 WithConcurrent
的重载添加子动画。
然后,通过调用 Commit
方法启动动画对象。
AnimationExtensions 类
AnimationExtensions
类主要包含扩展方法。 有多种版本的 Animate
方法,泛型 Animate
方法非常通用,因为它实际上是所需的唯一动画函数。
使用 Animation 类
ConcurrentAnimations 示例演示了具有多个不同动画的 Animation
类。
子动画
ConcurrentAnimations 示例还演示了子动画,这些子动画使用(非常类似的)Add
和 Insert
方法。
高级动画方法之外的内容
ConcurrentAnimations 示例还演示了如何执行超出 ViewExtensions
方法所针对的属性的动画。 在一个示例中,一系列周期变长;在另一个示例中,将对 BackgroundColor
属性进行动画处理。
自己的可等待方法的更多信息
ViewExtensions
的 TranslateTo
不适用于 Easing.SpringOut
函数。 当缓动输出大于 1 时,它将停止。
Xamarin.FormsBook.Toolkit 库包含 MoreViewExtensions
类,该类具有不存在此问题的 TranslateXTo
和 TranslateYTo
扩展方法,以及用于取消这些动画的 CancelTranslateXTo
和 CancelTranslateYTo
方法。
SpringSlidingEntrance 演示了 TranslateXTo
方法。
MoreExtensions
类还包含将 X 和 Y 转换结合的 TranslateXYTo
扩展方法以及 CancelTranslateXYTo
方法。
实现贝塞尔动画
也可以开发一个动画,使动画沿贝塞尔曲线的路径移动。 Xamarin.FormsBook.Toolkit 库包含 BezierSpline
结构,该结构封装贝塞尔曲线和 BezierTangent
枚举来控制方向。
MoreViewExtensions
类包含 BezierPathTo
扩展方法和 CancelBezierPathTo
方法。
BezierLoop 示例演示如何沿着贝塞尔路径对元素进行动画处理。
使用 AnimationExtensions
彩色动画是标准集合中缺少的一种动画类型。 问题在于,在两个 Color
值之间没有正确的插入方法。 可以插入单独的 RGB 值,但与插入 HSL 值的有效性相同。
因此,Xamarin.FormsBook.Toolkit 库中的 MoreViewExtensions
类包含两个 Color
动画方法:RgbColorAnimation
和 HslColorAnimation
。 (还有两种取消方法:CancelRgbColorAnimation
和 CancelHslColorAnimation
)。
这两种方法都使用 ColorAnimation
(通过调用 AnimationExtensions
中广泛的泛型 Animate
方法来执行动画)。
ColorAnimations 示例演示如何使用这两种彩色动画类型。
构造动画
用 XAML 表达动画并将动画与 MVVM 结合使用有时会很有用。 这将在下一章第 23 章触发器和行为中进行介绍。