你自己的等待动画
在本章的下一节中,您将看到Xamarin.Forms实现的基础动画基础结构。这些底层方法允许您定义自己的动画函数,这些函数返回Task对象,并且可以与await一起使用。
在第20章“异步和文件I / O”中,您了解了如何使用静态Task.Run方法创建执行的辅助线程,以执行像Mandelbrot计算这样的密集后台作业。 Task.Run方法返回一个Task对象,该对象可以在后台作业完成时发出信号。
但动画并不是那样的。动画不需要花费大量时间来处理数字。它只需要做一些非常简单和简单的事情 - 比如设置一个Rotation属性 - 每16毫秒一次。该作业可以在用户界面线程中运行 - 事实上,实际的属性访问必须在用户界面线程中运行 - 并且可以使用Device.StartTimer或Task.Delay来处理时间。
您不应该使用Task.Run来实现动画,因为执行的辅助线程是不必要的并且是浪费的。但是,当您实际坐下来编写类似于Xamarin.Forms动画方法(如RotateTo)的动画方法时,您可能会遇到障碍。该方法必须返回一个Task对象,并且可能使用Device.StartTimer作为计时,但这似乎不可能。
这是第一次尝试编写这样的方法。 参数包括目标VisualElement,from和to值以及持续时间。 它使用Device.StartTimer和Stopwatch来计算Rotation属性的当前设置,并在动画完成时退出Device.StartTimer回调:

Task MyRotate(VisualElement visual, double fromValue, double toValue, uint duration)
{Stopwatch stopwatch = new Stopwatch();stopwatch.Start();Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>{double t = Math.Min(1, stopwatch.ElapsedMilliseconds / (double)duration);double value = fromValue + t * (toValue - fromValue);visual.Rotation = value;bool completed = t == 1;if (completed){// Need to signal that the Task has completed. But how?}return !completed; });// Need to return a Task object here but where does it come from?
}

在两个关键点上,该方法不知道该怎么做。在方法调用Device.StartTimer之后,它需要退出并将Task对象返回给调用者。但是这个Task对象来自哪里? Task类有一个构造函数,但是像Task.Run一样,该构造函数创建了第二个执行线程,并且没有理由创建该线程。此外,当动画结束时,该方法需要以某种方式表示任务已完成。
幸运的是,存在一个完全符合您要求的类。 它叫做TaskCreationSource。 它是一个泛型类,其中type参数与要创建的Task对象的type参数相同。 askCreationSource对象的Task属性提供了您需要的Task对象。 这是您的异步方法返回的内容。 当您的方法完成处理后台作业时,它可以在TaskCreationSource对象上调用SetResult,表示作业已完成。
以下TryAwaitableAnimation程序显示如何在从Button的Clicked处理程序调用的MyRotateTo方法中使用TaskCreationSource:

public partial class TryAwaitableAnimationPage : ContentPage
{public TryAwaitableAnimationPage(){InitializeComponent();}async void OnButtonClicked(object sender, EventArgs args){Button button = (Button)sender;uint milliseconds = UInt32.Parse((string)button.StyleId);await MyRotate(button, 0, 360, milliseconds);}Task MyRotate(VisualElement visual, double fromValue, double toValue, uint duration){TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();Stopwatch stopwatch = new Stopwatch();stopwatch.Start();Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>{double t = Math.Min(1, stopwatch.ElapsedMilliseconds / (double)duration);double value = fromValue + t * (toValue - fromValue);visual.Rotation = value;bool completed = t == 1;if (completed){taskCompletionSource.SetResult(null);}return !completed; });return taskCompletionSource.Task;}
}

注意TaskCreationSource的实例化,该对象的Task属性的返回值,以及动画完成后对Device.StartTimer回调内的SetResult的调用。
TaskCreationSource没有非通用形式,因此如果您的方法只返回Task对象而不是Task 对象,则在定义TaskCreationSource实例时需要指定类型。 按照惯例,您可以使用object来实现此目的,在这种情况下,您的方法使用null参数调用SetResult。
TryAwaitableAnimation XAML文件实例化共享此Clicked处理程序的三个Button元素。 它们中的每一个都将自己的动画持续时间定义为StyleId属性。 (正如您所记得的,StyleId不在Xamarin.Forms中使用,仅供应用程序员使用,作为将任意数据附加到元素的便捷方式。)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="TryAwaitableAnimation.TryAwaitableAnimationPage"><StackLayout><StackLayout.Resources><ResourceDictionary><Style TargetType="Button"><Setter Property="Text" Value="Tap Me!" /><Setter Property="FontSize" Value="Large" /><Setter Property="HorizontalOptions" Value="Center" /><Setter Property="VerticalOptions" Value="CenterAndExpand" /></Style></ResourceDictionary></StackLayout.Resources><Button Clicked="OnButtonClicked" StyleId="5000" /><Button Clicked="OnButtonClicked" StyleId="2500" /><Button Clicked="OnButtonClicked" StyleId="1000" /></StackLayout>
</ContentPage>

即使这些Button元素中的每一个都通过调用MyRotate来设置动画,您也可以让所有按钮同时旋转。每次调用MyRotate都会获得自己的局部变量集,并在每个Device.StartTimer回调中使用这些局部变量。
但是,如果在按钮仍处于旋转状态时点击按钮,则会向该按钮应用第二个动画,并且两个动画相互争斗。代码需要的是在应用新动画时取消上一个动画的方法。
一种方法是MyRotate方法维护Dictionary 定义为字段。每当它开始动画时,MyRotate都会将目标VisualElement作为该字典的键添加,其值为false。动画结束时,它会从字典中删除此条目。一个单独的方法(可能名为CancelMyRotate)可以将字典中的值设置为true,这意味着取消动画。 Device.StartTimer回调可以通过检查特定VisualElement的字典值开始,如果动画已被取消,则从回调返回false。但是你会在讨论中发现如何用更少的代码来完成它。
现在您已经看到了ViewExtensions类中实现的高级动画函数,让我们来探讨Xamarin.Forms动画系统的其余部分如何实现这些函数
并允许您启动,控制和取消动画。

第二十二章:动画(十四)相关推荐

  1. Js高级程序设计第三版学习(十二章)

                                  Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3   1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...

  2. 第十二章 我国农村产业结构

    农村改革解说(专著)第十二章 第十二章 我国农村产业结构 1.什么是农村产业结构? 农村产业结构,是指在农村再生产过程中各经济部门之间和部门内各专业之间的技术经济联系与数量比例. 农村产业结构,有广义 ...

  3. stm32 文件系统dma大小_「正点原子NANO STM32F103开发板资料连载」第二十二章 DMA 实验...

    1)实验平台:[正点原子] NANO STM32F103 开发板 2)摘自<正点原子STM32 F1 开发指南(NANO 板-HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 ...

  4. 【信息系统项目管理师】第二十二章 信息系统安全管理(考点汇总篇)

    [信息系统项目管理师]第二十二章 信息系统安全管理(考点汇总篇) 考点分析与预测 信息安全为高级科目独有的章节,在第三版教材中有66页的内容.需要掌握的知识点非常多,且知识点非常散,在考试中上午一般考 ...

  5. 鸟哥的Linux私房菜(服务器)- 第二十二章、邮件服务器: Postfix

    第二十二章.邮件服务器: Postfix 最近更新日期:2011/08/10 在这个邮件服务器的架设中,我们首先谈论 Mail 与 DNS 的重要相关性,然后依序介绍 Mail Server 的相关名 ...

  6. 第二十二章 管理是一种文化活动

    第二十二章 管理是一种文化活动 作者:成君忆 第二十二章管理是一种文化活动 古者率民,必先礼信而后爵禄,先廉耻而后刑罚,先亲爱而后律其身.故战者必本乎率身以励众士,如心之使四肢也. ―<尉缭子& ...

  7. 游戏设计的艺术:一本透镜的书——第二十二章 其他玩家往往会形成社区

    这是一本游戏设计方面的好书 转自天之虹的博客:http://blog.sina.com.cn/jackiechueng 感谢天之虹的无私奉献 Word版可到本人的资源中下载 第二十二章其他玩家往往会形 ...

  8. 第二集 第一魂环 第十二章

    第二集 第一魂环 第十二章 乱披风锤法(一) 门口的两名门卫看上去都是二十岁左右的样子,身上的魂力波动并不明显,感觉上,似乎连魂师的级别都没有达到.看来,诺丁城果然是偏僻,从武魂殿的级别就能看出这座城 ...

  9. stm32l0的停止模式怎么唤醒_探索者 STM32F407 开发板资料连载第二十二章 待机唤醒实验

    1)实验平台:alientek 阿波罗 STM32F767 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第二十二章 待机唤醒实 ...

  10. 数字图像处理:第二十二章 基于模型的编码

    第二十二章基于模型的编码 目录 引言 基于对象的编码 基于模型的编码 作业 1. 引言 为了获得更高的压缩效率并保持一定的视频质量以支持超低码率(大约10kbps)双向视频应用,不考虑内容特点的仅仅针 ...

最新文章

  1. 盘点工业界AI项目流程以及边缘设备现状
  2. SylixOS DSP upgrade命令解析
  3. ssh: connect to host github.com port 22: Connection timed out
  4. WebStorm 常用快捷键大全 - 归纳总结篇
  5. poj2104 k-th number 主席树入门讲解
  6. rocketmq 几种队列_进阶必看的 RocketMQ ,就这篇了
  7. html代码格式化nodejs,使用Node编写的Sublime代码格式化工具插件(HTML/CSS/JS)
  8. Mysql like ' ' 会不会用到索引
  9. 我发现我对人类活动的认识开始有一点点变化了
  10. c 语言回调函数例子,C语言回调函数一个简单的例子
  11. 微信小程序地图插件系列(一):微信小程序使用高德地图(不定期更新)
  12. python爬取b站视频封面_我发现这个up封面确实有点东西,爬取B站视频的封面图片...
  13. 推荐一款好用的在线json格式化工具
  14. js连接蓝牙打印机打印一维码和二维码
  15. 百度地图在设置中心时,背景变白
  16. Linux 文档编辑 : let 命令详解
  17. 数据分类分析--聚类
  18. [激光原理与应用-39]:《光电检测技术-6》- 光干涉的原理与基础
  19. pg备份还原工具--pg_rman
  20. 微信开发者工具中使用scss

热门文章

  1. 多校第九场总结,树剖
  2. maven 常用插件3
  3. C/C++输入输出函数(I/O)总结
  4. @import注解使用
  5. 北大AI公开课2019 | 雷鸣:人工智能革命与机遇
  6. 【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效
  7. 5、【华为HCIE-Storage】--RAID类型
  8. ES6常用知识点概述
  9. python获取代码行号
  10. 微软笔试题 2013暑期实习笔试题目