第二十二章:动画(五)

简介: 等待动画解决后续点击问题的另一种方法是在调用RotateTo之前初始化Rotation属性:void OnButtonClicked(object sender, EventArgs args){ button.Rotation = 0; button.RotateTo(360, 2000);}现在,您可以在停止后再次点击按钮,它将从头开始动画。

等待动画
解决后续点击问题的另一种方法是在调用RotateTo之前初始化Rotation属性:

void OnButtonClicked(object sender, EventArgs args)
{
    button.Rotation = 0;
    button.RotateTo(360, 2000);
}

现在,您可以在停止后再次点击按钮,它将从头开始动画。 按钮旋转时重复点击也表现不同:它们从0度开始。
有趣的是,代码中的这种轻微变化不允许后续的点击:

void OnButtonClicked(object sender, EventArgs args)
{
    button.RotateTo(360, 2000);
    button.Rotation = 0;
}

此版本的行为与仅具有RotateTo方法的版本相同。 看起来似乎在该调用之后将Rotation属性设置为0。
为什么不起作用? 它不起作用,因为RotateTo方法是异步的。 启动动画后,该方法会快速返回,但动画本身会在后台发生。 在RotateTo方法返回时将Rotation属性设置为0没有明显的效果,因为
该设置很快被背景RotateTo动画取代。
因为该方法是异步的,所以RotateTo返回一个Task对象 - 更具体地说,返回一个Task 对象 - 这意味着您可以调用ContinueWith来指定动画终止时调用的回调函数。 然后,回调可以在动画完成后将Rotation属性设置为0:

void OnButtonClicked(object sender, EventArgs args)
{
    button.RotateTo(360, 2000).ContinueWith((task) =>
    {
        button.Rotation = 0;
    });
}

传递给ContinueWith的任务对象的类型为Task ,ContinueWith回调可以使用Result属性来获取该布尔值。 如果动画被取消,则值为true;如果动画完成,则该值为false。 您可以通过使用Debug.WriteLine调用显示返回值并在Visual Studio或Xamarin Studio的“输出”窗口中查看结果来轻松确认:

void OnButtonClicked(object sender, EventArgs args)
{
    button.RotateTo(360, 2000).ContinueWith((task) =>
    {
        System.Diagnostics.Debug.WriteLine("Cancelled? " + task.Result);
        button.Rotation = 0;
    });
}

如果在动画时点按按钮,您将看到返回的真值。 每次调用RotateTo都会取消之前的动画。 如果让动画运行完成,您将看到返回错误值。
使用RotateTo方法比使用ContinueWith更可能使用await:

async void OnButtonClicked(object sender, EventArgs args)
{
    bool wasCancelled = await button.RotateTo(360, 2000);
    button.Rotation = 0;
}

或者,如果您不关心返回值:

async void OnButtonClicked(object sender, EventArgs args)
{
    await button.RotateTo(360, 2000);
    button.Rotation = 0;
}

请注意处理程序上的async修饰符,这是包含await运算符的任何方法所必需的。
如果您使用过其他动画系统,如果您希望在动画完成时通知应用程序,则很可能需要定义回调方法。等待,确定动画何时完成 - 或许执行其他一些代码 - 变得微不足道。在这个特定的例子中,执行的代码非常简单,但当然它可能更复杂。
有时你会想让你的动画在后台运行完成 - 在这种情况下,没有必要使用等待它们 - 有时你会想要在动画完成时做一些事情。但请注意:如果Button也触发了一些实际的应用程序功能,您可能不想等到动画结束后再执行该操作。
RotateTo和RelRotateTo是ViewExtensions类中定义的几个类似方法中的两个。您将在本章中看到的其他内容包括ScaleTo,TranslateTo,FadeTo和LayoutTo。如果动画在没有中断的情况下完成,它们都返回Task objects-false,如果取消则返回true。
您的应用程序可以通过调用静态方法ViewExtensions.CancelAnimations取消这些动画中的一个或多个。与ViewExtensions中的所有其他方法不同,这不是扩展方法。你需要像这样调用它:

ViewExtensions.CancelAnimations(button)

这将立即取消由ViewExtensions类中当前在按钮对象上运行的扩展方法启动的所有动画。
使用await对于堆叠顺序动画特别有用:

async void OnButtonClicked(object sender, EventArgs args)
{
    await button.RotateTo(90, 250);
    await button.RotateTo(-90, 500);
    await button.RotateTo(0, 250);
}

此处定义的总动画需要一秒钟。按钮在第一个四分之一秒顺时针旋转90度,然后在下半秒逆时针旋转180度,然后顺时针旋转90度再次以0度结束。您需要等待前两个,以便它们是顺序的,但如果在第三个动画完成后没有其他任何东西可以在Clicked处理程序中执行,则您不需要它在第三个上。
像这样的复合动画通常被称为关键帧动画。您正在指定一系列旋转角度和时间,整个动画在这些之间进行插值。在大多数动画系统中,关键帧动画通常比简单动画更难使用。但随着等待,关键帧动画变得微不足道。
Task 的返回值不一定表示动画正在辅助线程中运行。实际上,动画的至少一部分 - 实际设置Rotation属性的部分 - 必须在用户界面线程中运行。从理论上讲,整个动画可以在用户界面线程中运行。正如您在上一章中看到的那样,使用Device.StartTimer或Task.Delay创建的动画完全在用户界面线程中运行,尽管底层计时器机制可能涉及辅助线程。
您将在本章后面看到动画方法如何仍然可以返回Task对象,但完全在用户界面线程中运行。此技术允许代码使用计时器来调整动画,但在代码完成时仍然提供基于任务的结构化通知。

目录
相关文章
|
JavaScript Android开发
第二十二章:动画(二十一)
使用AnimationExtensions为什么ViewExtensions不包含ColorTo动画? 这种方法没有你最初假设的那么明显有三个可能的原因:首先,VisualElement定义的唯一Color属性是BackgroundColor,但通常不是要设置动画的Color属性。
545 0
|
JavaScript Android开发
第二十二章:动画(二十)
实现贝塞尔动画一些图形系统实现动画,该动画沿着贝塞尔曲线移动视觉对象,甚至(可选地)旋转视觉对象,使其保持与曲线相切。Bezier曲线以法国工程师兼数学家PierreBézier的名字命名,他在雷诺工作期间开发了用于汽车车身交互式计算机辅助设计的曲线。
617 0
|
JavaScript Android开发
第二十二章:动画(十九)
更多你自己的等待方法之前,您已经了解了如何将TaskCompletionSource与Device.StartTimer一起使用来编写自己的异步动画方法。 您还可以将TaskCompletionSource与Animation类结合使用,编写自己的异步动画方法,类似于ViewExtensions类中的方法。
629 0
|
Android开发
第二十二章:动画(十八)
超越高级动画方法你到目前为止看到的ConcurrentAnimations中的例子仅限于Scale和Rotate属性的动画,因此它们没有显示任何你无法做的事情。ViewExtensions类中的方法。
702 0
|
Android开发
第二十二章:动画(十七)
子动画ConcurrentAnimations中的前两个示例是单个动画。 Animation类还支持子动画,这就是标记为“Animation 3”的Button的处理程序。 它首先使用无参数构造函数创建父动画对象。
681 0
|
JavaScript Android开发
第二十二章:动画(十五)
深入动画 在第一次遇到时,完整的Xamarin.Forms动画系统可能会有点混乱。 让我们从可用于定义动画的三个公共类的全局视图开始。整理课程除了Easing类之外,Xamarin.Forms动画系统还包含三个公共类。
823 0
|
JavaScript Android开发
第二十二章:动画(十六)
使用Animation类让我们对Animation类进行一些实验。 这涉及实例化Animation类型的对象,然后调用Commit,它实际上开始动画。 Commit方法不返回Task对象; 相反,Animation类完全通过回调提供通知。
705 0
|
JavaScript Android开发
第二十二章:动画(十)
你自己的缓和功能您可以轻松制作自己的缓动功能。所需要的只是一个类型为Func 的方法,它是一个带有double参数和double返回值的函数。这是一个传递函数:它应该为0的参数返回0,并且对于1的参数应该返回1.但是在这两个值之间,任何事情都会发生。
574 0
|
JavaScript Android开发
第二十二章:动画(九)
缓解功能你已经看过以下关键帧动画,它以一种方式摆动Button,然后是其他: async void OnButtonClicked(object sender, EventArgs args) { await button.RotateTo(90, 250); await button.RotateTo(-90, 500); await button.RotateTo(0, 250); } 但动画看起来并不合适。
941 0
|
JavaScript Android开发
第二十二章:动画(十四)
你自己的等待动画在本章的下一节中,您将看到Xamarin.Forms实现的基础动画基础结构。这些底层方法允许您定义自己的动画函数,这些函数返回Task对象,并且可以与await一起使用。在第20章“异步和文件I / O”中,您了解了如何使用静态Task.Run方法创建执行的辅助线程,以执行像Mandelbrot计算这样的密集后台作业。
711 0