本文共 3833 字,大约阅读时间需要 12 分钟。
跳跃和动画
ButtonJump程序主要用于演示无论您使用翻译在屏幕上移动按钮的位置,Button都会以正常方式响应按键。 XAML文件将Button放在页面中间(减去顶部的iOS填充):对于每次调用OnButtonClicked处理程序,代码隐藏文件将TranslationX和TranslationY属性设置为新值。 新值随机计算但受限制,以便Button始终保持在屏幕边缘:
public partial class ButtonJumpPage : ContentPage{ Random random = new Random(); public ButtonJumpPage() { InitializeComponent(); } void OnButtonClicked(object sender, EventArgs args) { Button button = (Button)sender; View container = (View)button.Parent; button.TranslationX = (random.NextDouble() - 0.5) * (container.Width - button.Width); button.TranslationY = (random.NextDouble() - 0.5) * (container.Height - button.Height); }}
例如,如果Button的宽度为80个单位,而ContentView的宽度为320个单位,则差异为240个单位,当Button位于ContentView的中心时,Button的每一侧为120个单位。 Random的NextDouble方法返回0到1之间的数字,减去0.5会产生介于-0.5和0.5之间的数字,这意味着TranslationX被设置为介于-120和120之间的随机值。这些值可能将Button定位到屏幕的边缘,但没有超越。
请记住,TranslationX和TranslationY是属性而不是方法。它们不是累积的。如果将TranslationX设置为100然后设置为200,则视觉元素不会从其布局位置偏移总共300个单位。第二个TranslationX值200替换而不是添加到初始值100。使用ButtonJump程序几秒钟可能会引发一个问题:这可以动画吗? Button可以滑向新点而不是简单地跳到那里吗?当然。有几种方法可以做,包括下一章讨论的Xamarin.Forms动画方法。 ButtonGlide程序中的XAML文件与ButtonJump中的XAML文件相同,只是Button现在有一个名称,以便程序可以在Clicked处理程序之外轻松引用它:代码隐藏文件通过将几个基本信息保存为字段来处理按钮单击:指示从TranslationX和TranslationY的当前值获得的起始位置的点; 通过从随机目的地点减去该起点计算的矢量(也是点值); 和单击按钮时的当前DateTime:
public partial class ButtonGlidePage : ContentPage{ static readonly TimeSpan duration = TimeSpan.FromSeconds(1); Random random = new Random(); Point startPoint; Point animationVector; DateTime startTime; public ButtonGlidePage() { InitializeComponent(); Device.StartTimer(TimeSpan.FromMilliseconds(16), OnTimerTick); } void OnButtonClicked(object sender, EventArgs args) { Button button = (Button)sender; View container = (View)button.Parent; // The start of the animation is the current Translation properties. startPoint = new Point(button.TranslationX, button.TranslationY); // The end of the animation is a random point. double endX = (random.NextDouble() - 0.5) * (container.Width - button.Width); double endY = (random.NextDouble() - 0.5) * (container.Height - button.Height); // Create a vector from start point to end point. animationVector = new Point(endX - startPoint.X, endY - startPoint.Y); // Save the animation start time. startTime = DateTime.Now; } bool OnTimerTick() { // Get the elapsed time from the beginning of the animation. TimeSpan elapsedTime = DateTime.Now - startTime; // Normalize the elapsed time from 0 to 1. double t = Math.Max(0, Math.Min(1, elapsedTime.TotalMilliseconds / duration.TotalMilliseconds)); // Calculate the new translation based on the animation vector. button.TranslationX = startPoint.X + t * animationVector.X; button.TranslationY = startPoint.Y + t * animationVector.Y; return true; }}
每16毫秒调用一次定时器回调。那不是一个随意的数字!视频显示器的硬件刷新率通常为每秒60次。因此,每帧都有效约16毫秒。以此速率播放动画是最佳选择。每16毫秒一次,回调计算从动画开始经过的时间,并将其除以持续时间。这是一个通常称为t(时间)的值,在动画过程中范围从0到1。此值乘以向量,结果将添加到startPoint。这是TranslationX和TranslationY的新价值。
虽然在应用程序运行时会连续调用计时器回调,但是当动画完成时,TranslationX和TranslationY属性将保持不变。但是,您不必等到Button停止移动才能再次点击它。 (您需要快速,或者您可以将持续时间属性更改为更长的时间。)新动画从Button的当前位置开始,并完全替换上一个动画。计算t的归一化值的一个优点是,修改该值变得相当容易,因此动画不具有恒定的速度。例如,尝试在初始计算t之后添加此语句:t = Math.Sin(t * Math.PI / 2);
当动画开始时t的原始值为0时,Math.Sin的参数为0,结果为0.当t的原始值为1时,Math.Sin的参数为π/ 2,并且 结果是1.但是,这两点之间的值不是线性的。 当t的初始值为0.5时,该语句将t重新计算为45度的正弦值,即0.707。 因此,当动画结束一半时,Button已经将70%的距离移动到目的地。 总的来说,你会看到一个动画在开始时更快,到最后更慢。
在本章中,您将看到几种不同的动画方法。 即使您已经熟悉Xamarin.Forms提供的动画系统,有时候自己动手也很有用。转载地址:http://twtjl.baihongyu.com/