跳躍和動畫
ButtonJump程序主要用於演示無論您使用翻譯在屏幕上移動按鈕的位置,Button都會以正常方式響應按鍵。 XAML文件將Button放在頁面中間(減去頂部的iOS填充):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonJump.ButtonJumpPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentView>
<Button Text="Tap me!"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center"
Clicked="OnButtonClicked" />
</ContentView>
</ContentPage>
對於每次調用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處理程序之外輕鬆引用它:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonGlide.ButtonGlidePage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentView>
<Button x:Name="button"
Text="Tap me!"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center"
Clicked="OnButtonClicked" />
</ContentView>
</ContentPage>
代碼隱藏文件通過將幾個基本信息保存爲字段來處理按鈕單擊:指示從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提供的動畫系統,有時候自己動手也很有用。