第二種方法,CompositionTarget動畫,官方描述為:CompositionTarget對象可以根據每個幀回調來創建自定義動畫。其實直接點,CompositionTarget創建的動畫是基於每次界面刷新後觸發的,與窗體刷新率保持一致,所以頻率是固定的,很難人工介入控制。
那麼如何使用它?xaml的界面代碼還是和上一篇中描述的一樣,這裡不累述了。那麼接下來就是創建對象並注冊事件,全部代碼如下:
Rectangle rect; //創建一個方塊作為演示對象
double speed = 1; //設置移動速度
Point moveTo; //設置移動目標
public Window1() {
InitializeComponent();
rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Red);
rect.Width = 50;
rect.Height = 50;
rect.RadiusX = 5;
rect.RadiusY = 5;
Carrier.Children.Add(rect);
Canvas.SetLeft(rect, 0);
Canvas.SetTop(rect, 0);
//注冊界面刷新事件
CompositionTarget.Rendering += new EventHandler(Timer_Tick);
}
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
moveTo = e.GetPosition(Carrier);
}
CompositionTarget的注冊事件方法為:
CompositionTarget.Rendering += new EventHandler(Timer_Tick);
因為我們要實現的是鼠標點哪方塊就移動到哪,所以我用一個變量moveTo保存鼠標點擊點的Point。並在鼠標左鍵事件中賦值:moveTo = e.GetPosition(Carrier);同時設置方塊X,Y方向的速度均為speed。
接下來就是實現Timer_Tick了,它是基於窗體的時時刷新事件。我們這樣寫:
private void Timer_Tick(object sender, EventArgs e) {
double rect_X = Canvas.GetLeft(rect);
double rect_Y = Canvas.GetTop(rect);
Canvas.SetLeft(rect, rect_X + (rect_X < moveTo.X ? speed : -speed));
Canvas.SetTop(rect, rect_Y + (rect_Y < moveTo.Y ? speed : -speed));
}
首先獲取方塊的X,Y位置,接下讓方塊的X,Y與moveTo的X,Y進行比較而判斷是+speed還是-speed,這裡的邏輯需要朋友們自行領會了。
好了Ctrl+F5測試一下,呵呵,是不是同樣也動起來了呢?
可是大家會發現一個很大的問題:這方塊移動得也太勉強了吧,抖來抖去的而且移動得也不平滑,是不是CompositionTarget有問題?其實不然,因為之前的Storyboard動畫它不存在X,Y軸的速度,只需要設定起點和終點以及過程經歷的時間就可以平滑的移動了,而CompositionTarget需要分別設定X,Y軸的速度,而我們這為了簡單演示,X,Y軸的速度speed均設置成了5,這在現實使用中是絕對不合理的。因此,如果要模擬實際效果,必須計算終點和起點的正切值Tan,然後再根據直線速度speed通過Tan值計算出speed_X,speed_Y,最後改寫成:
Canvas.SetLeft(rect, rect_X + (rect_X < moveTo.X ? speed_X : -speed_X));
Canvas.SetTop(rect, rect_Y + (rect_Y < moveTo.Y ? speed_Y : -speed_Y));
這樣才能實現真實的移動(具體算法就不討論了)。
這一節講解了如何使用CompositionTarget主界面刷新線程實現基於幀的動畫,下一節我將講解第三種動態創建動畫的方法,並會對這三種方法進行一個歸納比較。