自定义动画
Animation类是所有Xamarin.Forms动画的构建块,ViewExtensions类中的扩展方法创建一个或多个Animation对象。本文演示如何使用Animation类创建和取消动画,同步多个动画,并创建自定义动画,使动画的属性不被现有的动画方法动画化。
概观
创建Animation
对象时必须指定多个参数,包括动画属性的开始和结束值以及更改属性值的回调。一个Animation
物体也能保持可运行和同步的儿童动画的集合。有关更多信息,请参阅儿童动画。
Animation
通过调用该Commit
方法,可以运行使用该类创建的动画(可能包含或不包含子动画)。此方法指定动画的持续时间,以及其他项目之间的控制是否重复动画的回调。
创建动画
在创建Animation
对象时,通常需要至少三个参数,如下面的代码示例所示:
var animation = new Animation (v => image.Scale = v, 1, 2);
该代码将一个实例Scale
属性的动画Image
从值1定义为值2.由Xamarin.Forms派生的动画值被传递给指定为第一个参数的回调,用于更改Scale
物业的价值。
通过调用该Commit
方法开始动画,如下面的代码示例所示:
animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);
请注意,该Commit
方法不返回Task
对象。相反,通过回调方法提供通知。
以下参数在Commit
方法中指定:
- 第一个参数(owner)标识动画的所有者。这可以是应用动画的视觉元素,或其他视觉元素,如页面。
- 第二个参数(name)用一个名称标识动画。该名称与所有者结合以唯一标识动画。然后可以使用该唯一标识来确定动画是正在运行(
AnimationIsRunning
)还是取消它(AbortAnimation
)。 - 第三个参数(rate)表示在
Animation
构造函数中定义的每个调用回调方法之间的毫秒数 - 第四个参数(length)表示动画的持续时间,以毫秒为单位。
- 第五个参数(简化)定义了动画中要使用的缓动函数。或者,可以将缓动函数指定为
Animation
构造函数的参数。有关宽松功能的更多信息,请参阅缓动功能。 - 第六个参数(finished)是一个回调,当动画完成时将执行。这个回调函数有两个参数,第一个参数表示一个最终值,第二个参数
bool
设置为true
动画被取消。或者,完成的回调可以被指定为Animation
构造函数的参数。但是,使用单个动画,如果在构造函数和方法中都指定了完成的回调,则只会执行该方法中指定的回调。Animation
Commit
Commit
- 第七个参数(重复)是一个回调,允许重复动画。它在动画结束时被调用,返回
true
表示应该重复动画。
整体效果是使用缓动功能创建一个将Scale
属性Image
从1增加到2秒(2000毫秒)的动画Linear
。每次动画完成后,其Scale
属性将重置为1,并重复动画。
可以通过Animation
为每个动画创建一个对象,然后Commit
在每个动画上调用该方法来构建彼此独立运行的并行动画。
子动画
该Animation
班还支持子动画,这涉及到创建Animation
到其他对象Animation
添加的对象。这样可以运行和同步一系列动画。以下代码示例演示如何创建和运行子动画:
var parentAnimation = new Animation ();
var scaleUpAnimation = new Animation (v => image.Scale = v, 1, 2, Easing.SpringIn);
var rotateAnimation = new Animation (v => image.Rotation = v, 0, 360);
var scaleDownAnimation = new Animation (v => image.Scale = v, 2, 1, Easing.SpringOut);
parentAnimation.Add (0, 0.5, scaleUpAnimation);
parentAnimation.Add (0, 1, rotateAnimation);
parentAnimation.Add (0.5, 1, scaleDownAnimation);
parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));
或者,代码示例可以更简洁地写出,如下面的代码示例所示:
new Animation {
{ 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
{ 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
{ 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
}.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));
在两个代码示例中,Animation
创建一个父对象,Animation
然后添加其他对象。该Add
方法的前两个参数指定何时开始和完成子动画。参数值必须在0和1之间,并且表示父动画中指定的子动画将处于活动状态的相对周期。因此,在这个例子scaleUpAnimation
中,动画的前半部分scaleDownAnimation
将被激活,动画的下半部分rotateAnimation
将被激活,并且整个持续时间将被激活。
整体效果是动画发生超过4秒(4000毫秒)。在scaleUpAnimation
所述动画Scale
属性从1到2,经2秒。所述scaleDownAnimation
然后动画的Scale
属性从2到1,经2秒。虽然这两种缩放动画正在发生,rotateAnimation
动画的Rotation
属性从0到360,超过4秒。请注意,缩放动画也使用缓动功能。在SpringIn
宽松的功能使Image
最初越来越大前收缩和SpringOut
放松功能使Image
变得比实现全面动画结束它的实际尺寸。
Animation
使用子动画 的对象之间存在许多不同之处:
- 当使用子动画时,子动画上的完成的回调指示孩子何时完成,并且传递给该方法的完成的回调
Commit
指示整个动画何时完成。 - 当使用子动画时,
true
从方法上的重复回调返回Commit
不会导致动画重复,但动画将继续运行而没有新值。 - 当在
Commit
方法中包含一个缓动函数,并且缓动函数返回大于1的值时,动画将被终止。如果缓动函数返回小于0的值,则该值被钳制为0.要使用返回小于0或大于1的值的缓动函数,必须在其中一个子动画中指定,而不是在Commit
方法中指定。
本Animation
类还包括WithConcurrent
可用于儿童动画添加到父方法Animation
的对象。但是,它们的开始和结束参数值不限于0到1,但只有对应于0到1范围的子动画的那部分将是活动的。例如,如果一个WithConcurrent
方法调用定义了一个子动画靶向Scale
1-6属性,但与开始和结束的-2和3的值,则开始 -2值对应于Scale
值1,并且结束的值3对应于Scale
值6.由于0和1范围之外的值不会在动画中播放,因此该Scale
属性将仅从3到6的动画。
取消动画
应用程序可以通过调用AbortAnimation
扩展方法来取消动画,如下面的代码示例所示:
this.AbortAnimation ("SimpleAnimation");
请注意,动画所有者和动画名称的组合唯一标识动画。因此,必须指定运行动画时指定的所有者和名称才能取消动画。因此,代码示例将立即取消SimpleAnimation
页面所拥有的动画。
创建自定义动画
到目前为止,这里显示的示例已经展示了可以通过ViewExtensions
类中的方法同样实现的动画。但是,Animation
该类的优点是它可以访问回调方法,该方法在动画值更改时执行。这允许回调来实现任何所需的动画。例如,以下代码示例BackgroundColor
通过将页面的属性设置为Color
通过Color.FromHsla
方法创建的值来动画化属性,其中色调值的范围为0到1:
new Animation (callback: v => BackgroundColor = Color.FromHsla (v, 1, 0.5),
start: 0,
end: 1).Commit (this, "Animation", 16, 4000, Easing.Linear, (v, c) => BackgroundColor = Color.Default);
所产生的动画提供通过彩虹的颜色推进页面背景的外观。
为了创建复杂的动画,包括贝塞尔曲线动画的更多示例,请参见第22章的与Xamarin.Forms创建移动应用程序。
创建自定义动画扩展方法
类中的扩展方法ViewExtensions
将属性从其当前值转换为指定值。这使得很难创建例如ColorTo
可以用于将颜色从一个值赋给另一个值的动画方法,因为:
- 该类
Color
定义的唯一属性VisualElement
是BackgroundColor
,并不总是Color
动画所需的属性。 - 通常,
Color
属性的当前值Color.Default
不是真正的颜色,并且不能用于插值计算。
解决这个问题的ColorTo
方法是没有一个特定的Color
属性的方法。相反,它可以使用将内插值传递Color
给调用者的回调方法来编写。此外,该方法将采用开始和结束Color
参数。
该ColorTo
方法可以实现为使用类中的Animate
方法AnimationExtensions
来提供其功能的扩展方法。这是因为该Animate
方法可用于定位不是类型的属性double
,如以下代码示例所示:
public static class ViewExtensions
{
public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color> callback, uint length = 250, Easing easing = null)
{
Func<double, Color> transform = (t) =>
Color.FromRgba(fromColor.R + t * (toColor.R - fromColor.R),
fromColor.G + t * (toColor.G - fromColor.G),
fromColor.B + t * (toColor.B - fromColor.B),
fromColor.A + t * (toColor.A - fromColor.A));
return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
}
public static void CancelAnimation(this VisualElement self)
{
self.AbortAnimation("ColorTo");
}
static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform, Action<Color> callback, uint length, Easing easing)
{
easing = easing ?? Easing.Linear;
var taskCompletionSource = new TaskCompletionSource<bool>();
element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
return taskCompletionSource.Task;
}
}
该Animate
方法需要一个转换参数,这是一个回调方法。此回调的输入始终double
为0到1.因此,该ColorTo
方法定义其自身的变换Func
,接受double
范围从0到1,并返回与该Color
值对应的值。所述Color
值通过内插所计算的R
,G
,B
,和A
的两个提供的值Color
的参数。Color
然后将该值传递给回调方法以应用于特定属性。
这种方法允许ColorTo
方法为任何Color
属性生成动画,如下面的代码示例所示:
await Task.WhenAll(
label.ColorTo(Color.Red, Color.Blue, c => label.TextColor = c, 5000),
label.ColorTo(Color.Blue, Color.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Color.Blue, Color.Red, c => boxView.Color = c, 4000);
在该代码示例中,ColorTo
方法的动画TextColor
和BackgroundColor
的性质Label
的,BackgroundColor
一个页面的属性和Color
的特性BoxView
。
概要
本文演示了如何使用Animation
类来创建和取消动画,同步多个动画,并创建自定义动画,使动画的属性不被现有的动画方法动画化。该Animation
课程是所有Xamarin.Forms动画的构建块。