共用方式為


中的自訂動畫 Xamarin.Forms

Animation 類別是所有 Xamarin.Forms 動畫的建置組塊,而 ViewExtensions 類別中的擴充方法會建立一或多個 Animation 物件。 本文示範如何使用 Animation 類別來建立和取消動畫、同步處理多個動畫,以及建立自定義動畫,以動畫顯示現有動畫方法未產生動畫的屬性。

建立 Animation 物件時必須指定一些參數,包括要產生動畫之屬性的開始和結束值,以及變更屬性值的回呼。 Animation物件也可以維護可執行和同步處理的子動畫集合。 如需詳細資訊,請參閱 子動畫

藉由呼叫 Commit 方法,執行以 Animation 類別建立的動畫,其中不一定包含子動畫。 這個方法會指定動畫的持續時間,以及其他專案,可控制是否要重複動畫的回呼。

此外,類別 Animation 具有 IsEnabled 可檢查的屬性,以判斷操作系統是否已停用動畫,例如啟用省電模式時。

建立動畫

建立 Animation 物件時,通常至少需要三個參數,如下列程式代碼範例所示:

var animation = new Animation (v => image.Scale = v, 1, 2);

此程式代碼會定義實例屬性Image的動畫Scale,從1值到2的值。 由衍生 Xamarin.Forms的動畫值會傳遞至指定為第一個自變數的 Scale 回呼,用來變更 屬性的值。

動畫是以呼叫 Commit 方法開始,如下列程式代碼範例所示:

animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);

請注意, Commit 方法不會傳回 Task 物件。 相反地,通知會透過回呼方法提供。

方法中 Commit 指定了下列自變數:

  • 第一個自變數 (owner) 會識別動畫的擁有者。 這可以是套用動畫的視覺專案,或是另一個視覺元素,例如頁面。
  • 第二個自變數 (name) 會以名稱識別動畫。 名稱會與擁有者結合,以唯一識別動畫。 然後,這個唯一的識別可用來判斷動畫是否正在執行或AnimationIsRunning取消它 (AbortAnimation)。
  • 第三個自變數 (rate) 表示建構函式中所 Animation 定義回呼方法的每個呼叫之間的毫秒數。
  • 第四個自變數 (length) 表示動畫的持續時間,以毫秒為單位。
  • 第五個自變數 (easing) 定義要用於動畫中的 easing 函式。 或者,可以將 easing 函式指定為建構函式的 Animation 自變數。 如需 Easing 函式的詳細資訊,請參閱 Easing 函式
  • 第六個自變數(已完成)是一個回呼,會在動畫完成時執行。 此回呼會採用兩個自變數,第一個自變數表示最終值,而第二個 bool 自變數則為已設定為 ,如果取消動畫,則為 true 。 或者,完成回呼也可以指定為建構函式的Animation自變數。 不過,使用單一動畫時,如果在建構函式和 Commit 方法中Animation指定完成的回呼,則只會執行 方法中指定的Commit回呼。
  • 第七個自變數 (repeat) 是可讓動畫重複的回呼。 它會在動畫結尾呼叫,並傳 true 回表示應該重複動畫。

整體效果是建立動畫,使用 Linear easing 函式將 的 屬性Image從 1 增加到 Scale 2,超過 2 秒(2000 毫秒)。 每次動畫完成時,其 Scale 屬性都會重設為 1,而動畫會重複。

注意

並行動畫可以藉由為每個動畫建立 Animation 物件,然後在每個動畫上呼叫 Commit 方法,來建構彼此獨立執行的動畫。

子動畫

類別 Animation 也支持子動畫,其牽涉到建立 Animation 加入其他 Animation 對象的物件。 這可讓一系列動畫執行並同步處理。 下列程式代碼範例示範如何建立和執行子動畫:

var parentAnimation = new Animation ();
var scaleUpAnimation = new Animation (v => image.Scale = v, 1, 2, Easing.SpringIn);
var rotateAnimation = new Animation (v => image.Rotation = v, 0, 360);
var scaleDownAnimation = new Animation (v => image.Scale = v, 2, 1, Easing.SpringOut);

parentAnimation.Add (0, 0.5, scaleUpAnimation);
parentAnimation.Add (0, 1, rotateAnimation);
parentAnimation.Add (0.5, 1, scaleDownAnimation);

parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));

或者,程式代碼範例可以更簡潔地撰寫,如下列程式代碼範例所示:

new Animation {
    { 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
    { 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
    { 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
    }.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));

在這兩個程式代碼範例中,都會建立父 Animation 對象,然後新增其他 Animation 物件。 方法的前兩個自變數 Add 會指定何時開始和完成子動畫。 自變數值必須介於 0 到 1 之間,並代表指定子動畫將使用中之父動畫內的相對期間。 因此,在此範例中, scaleUpAnimation 會針對動畫的前半部使用中、 scaleDownAnimation 將作用中動畫的下半部,而且 rotateAnimation 會在整個期間內為使用中。

整體效果是動畫發生在 4 秒 (4000 毫秒) 以上。 將 scaleUpAnimation 屬性從 1 到 2 產生動畫 Scale 效果,超過 2 秒。 接著,ScalescaleDownAnimation 屬性從 2 到 1 產生動畫效果,超過 2 秒。 雖然發生這兩個縮放動畫,但 rotateAnimation 屬性會從 0 到 360 產生動畫 Rotation 效果,超過 4 秒。 請注意,縮放動畫也會使用 Easing 函式。 Easing 函 SpringIn 式會在 Image 開始縮小之前先縮小,而 SpringOut Easing 函式會使 Image 變成小於其完整動畫結尾的實際大小。

使用子動畫的物件與不使用子動畫的物件之間 Animation 有許多差異:

  • 使用子動畫時,子動畫的完成回呼會指出子系完成的時間,而傳遞至 Commit 方法的完成回呼會指出整個動畫完成的時間。
  • 使用子動畫時,從方法上的Commit重複回呼傳回true不會造成動畫重複,但動畫會繼續執行,而不會有新的值。
  • 在方法中包含 Commit easing 函式,而 easing 函式傳回大於 1 的值時,動畫將會終止。 如果 easing 函式傳回小於 0 的值,該值會限製為 0。 若要使用傳回小於 0 或大於 1 值的 Easing 函式,它必須在其中一個子動畫中指定,而不是在 方法中 Commit 指定。

類別 Animation 也包含 WithConcurrent 可用來將子動畫新增至父 Animation 物件的方法。 不過,其 開始完成 自變數值不限於 0 到 1,但只有對應至 0 到 1 範圍的子動畫部分才會作用中。 例如,如果WithConcurrent方法呼叫定義以 1 到 6 之屬性為目標Scale的子動畫,但以 -2 和 3 的開頭完成值為目標,則 -2 的開始值會對應至 Scale 1 的值,而完成值為 3 會對應至 Scale 6 的值。 因為介於 0 和 1 以外的值在動畫中沒有作用, Scale 因此屬性只會以動畫顯示從 3 到 6。

取消動畫

應用程式可以使用對擴充方法的呼叫 AbortAnimation 來取消動畫,如下列程式代碼範例所示:

this.AbortAnimation ("SimpleAnimation");

請注意,動畫是由動畫擁有者與動畫名稱的組合唯一識別。 因此,必須指定執行動畫時所指定的擁有者和名稱,才能取消動畫。 因此,程式代碼範例會立即取消頁面所擁有的動畫 SimpleAnimation

建立自定義動畫

到目前為止所示範的範例示範了可以同樣透過 類別中 ViewExtensions 方法達成之動畫。 不過,類別的優點 Animation 是它可以存取回呼方法,而這個方法會在動畫值變更時執行。 這可讓回呼實作任何所需的動畫。 例如,下列程式代碼範例會將頁面的 屬性設定為 方法所Color.FromHsla建立的值,其色調值範圍從 0 到 Color 1,以動畫BackgroundColor顯示頁面的 屬性:

new Animation (callback: v => BackgroundColor = Color.FromHsla (v, 1, 0.5),
  start: 0,
  end: 1).Commit (this, "Animation", 16, 4000, Easing.Linear, (v, c) => BackgroundColor = Color.Default);

產生的動畫提供透過彩虹色彩來推進頁面背景的外觀。

如需建立複雜動畫的更多範例,包括 Bezier 曲線動畫,請參閱使用 Xamarin.Forms建立 Mobile Apps 第 22 章。

建立自定義動畫擴充方法

類別中的 ViewExtensions 擴充方法會將屬性從其目前值動畫到指定的值。 例如, ColorTo 這可讓您難以建立動畫方法,可用來建立一個值到另一個值之色彩的動畫方法,因為:

此問題的解決方案是沒有 ColorTo 方法以特定 Color 屬性為目標。 相反地,可以使用回呼方法撰寫,將插補 Color 值傳回給呼叫端。 此外,方法會採用 start 和 end Color 自變數。

方法 ColorTo 可以實作為擴充方法,該方法會使用 Animate 類別中的 AnimationExtensions 方法來提供其功能。 這是因為 Animate 方法可用來以不是 類型的 double屬性為目標,如下列程式代碼範例所示:

public static class ViewExtensions
{
  public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color> callback, uint length = 250, Easing easing = null)
  {
    Func<double, Color> transform = (t) =>
      Color.FromRgba(fromColor.R + t * (toColor.R - fromColor.R),
                     fromColor.G + t * (toColor.G - fromColor.G),
                     fromColor.B + t * (toColor.B - fromColor.B),
                     fromColor.A + t * (toColor.A - fromColor.A));
    return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
  }

  public static void CancelAnimation(this VisualElement self)
  {
    self.AbortAnimation("ColorTo");
  }

  static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform, Action<Color> callback, uint length, Easing easing)
  {
    easing = easing ?? Easing.Linear;
    var taskCompletionSource = new TaskCompletionSource<bool>();

    element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
    return taskCompletionSource.Task;
  }
}

方法 Animate 需要 轉換 自變數,這是回呼方法。 這個回呼的輸入一律 double 介於 0 到 1。 因此, ColorTo 方法會定義它自己的轉換 Func ,接受 double 範圍從 0 到 1 的 ,並傳 Color 回對應至該值的值。 值Color是藉由插補兩個提供的Color自變數、RGBA 值來計算。 然後,值 Color 會傳遞至應用程式的回呼方法至特定屬性。

此方法可讓 ColorTo 方法產生任何 Color 屬性的動畫效果,如下列程式代碼範例所示:

await Task.WhenAll(
  label.ColorTo(Color.Red, Color.Blue, c => label.TextColor = c, 5000),
  label.ColorTo(Color.Blue, Color.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Color.Blue, Color.Red, c => boxView.Color = c, 4000);

在此程式代碼範例中 ColorTo ,方法會以動畫顯示 TextColor 的和 BackgroundColor 屬性 LabelBackgroundColor 頁面的 屬性,以及 ColorBoxView屬性。