日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第二十二章:动画(十四)

發布時間:2025/6/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第二十二章:动画(十四) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

你自己的等待動畫
在本章的下一節中,您將看到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動畫系統的其余部分如何實現這些函數
并允許您啟動,控制和取消動畫。

總結

以上是生活随笔為你收集整理的第二十二章:动画(十四)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。