Sdílet prostřednictvím


Vlastní animace v Xamarin.Forms

Třída Animation je stavební blok všech Xamarin.Forms animací, s rozšiřujícími metodami ve třídě ViewExtensions vytvářející jeden nebo více animačních objektů. Tento článek ukazuje, jak pomocí třídy Animace vytvářet a rušit animace, synchronizovat více animací a vytvářet vlastní animace, které animují vlastnosti, které nejsou animované existujícími metodami animace.

Při vytváření objektu Animation , včetně počátečních a koncových hodnot animované vlastnosti, a zpětného volání, které změní hodnotu vlastnosti, musí být zadáno několik parametrů. Objekt Animation může také udržovat kolekci podřízených animací, které lze spustit a synchronizovat. Další informace naleznete v tématu Podřízené animace.

Spuštění animace vytvořené pomocí Animation třídy, která může nebo nemusí obsahovat podřízené animace, je dosaženo voláním Commit metody. Tato metoda určuje dobu trvání animace a mimo jiné zpětné volání, které řídí, zda se má animace opakovat.

Kromě toho třída má IsEnabled vlastnost, kterou lze prozkoumat a určit, Animation zda byly animace zakázány operačním systémem, například při aktivaci režimu úspory energie.

Vytvoření animace

Při vytváření objektu Animation se obvykle vyžaduje minimálně tři parametry, jak je znázorněno v následujícím příkladu kódu:

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

Tento kód definuje animaci Scale vlastnosti Image instance z hodnoty 1 na hodnotu 2. Animované hodnoty, které jsou odvozeny Xamarin.Forms, je předán zpět zpětné volání zadané jako první argument, kde se používá ke změně hodnoty Scale vlastnosti.

Animace se spustí voláním Commit metody, jak je znázorněno v následujícím příkladu kódu:

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

Všimněte si, že Commit metoda nevrací Task objekt. Místo toho se oznámení poskytují prostřednictvím metod zpětného volání.

V metodě jsou zadány Commit následující argumenty:

  • První argument (vlastník) identifikuje vlastníka animace. Může se jednat o vizuální prvek, na kterém se animace použije, nebo jiný vizuální prvek, například stránku.
  • Druhý argument (název) identifikuje animaci s názvem. Jméno se zkombinuje s vlastníkem a jedinečně identifikuje animaci. Tuto jedinečnou identifikaci pak můžete použít k určení, jestli je animace spuštěná (AnimationIsRunning) nebo jestli ji chcete zrušit (AbortAnimation).
  • Třetí argument (sazba) označuje počet milisekund mezi každým voláním metody zpětného volání definovanou v konstruktoru Animation .
  • Čtvrtý argument (délka) označuje dobu trvání animace v milisekundách.
  • Pátý argument (easing) definuje funkci usnadnění, která se má použít v animaci. Případně lze funkci easing zadat jako argument konstruktoru Animation . Další informace o usnadnění funkcí najdete v tématu Easing Functions.
  • Šestý argument (dokončený) je zpětné volání, které se spustí po dokončení animace. Tento zpětný volání přebírá dva argumenty, přičemž první argument označuje konečnou hodnotu a druhý argument je bool nastavený na true hodnotu, pokud byla animace zrušena. Případně lze dokončené zpětné volání zadat jako argument konstruktoruAnimation. Pokud jsou však dokončené zpětné volání zadány v Animation konstruktoru Commit i metodě, spustí se pouze zpětné volání zadané v Commit metodě.
  • Sedmý argument (opakovat) je zpětné volání, které umožňuje opakování animace. Volá se na konci animace a návrat true označuje, že by se animace měla opakovat.

Celkovým efektem je vytvoření animace, která pomocí funkce easing zvýší Scale vlastnost Image z 1 na 2 sekundy (2000 milisekund Linear ). Pokaždé, když se animace dokončí, Scale její vlastnost se obnoví na hodnotu 1 a animace se opakuje.

Poznámka:

Souběžné animace, které běží nezávisle na sobě, lze vytvořit vytvořením objektu Animation pro každou animaci a následným voláním Commit metody pro každou animaci.

Podřízené animace

Třída Animation také podporuje podřízené animace, které zahrnují vytvoření objektu Animation , do kterého jsou přidány další Animation objekty. To umožňuje spustit a synchronizovat řadu animací. Následující příklad kódu ukazuje vytváření a spouštění podřízených animací:

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));

Příklad kódu lze také napsat výstižněji, jak je znázorněno v následujícím příkladu kódu:

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));

V obou příkladech kódu se vytvoří nadřazený Animation objekt, do kterého se pak přidají další Animation objekty. První dva argumenty Add metody určují, kdy začít a dokončit podřízenou animaci. Hodnoty argumentů musí být v rozmezí od 0 do 1 a představují relativní období v rámci nadřazené animace, kterou bude zadaná podřízená animace aktivní. Proto v tomto příkladu scaleUpAnimation bude aktivní pro první polovinu animace, scaleDownAnimation bude aktivní pro druhou polovinu animace a rotateAnimation bude aktivní po celou dobu trvání.

Celkový efekt spočívá v tom, že animace trvá více než 4 sekundy (4000 milisekund). Animuje scaleUpAnimation Scale vlastnost od 1 do 2, více než 2 sekundy. Potom scaleDownAnimation animuje Scale vlastnost od 2 do 1, více než 2 sekundy. I když se vyskytují obě animace škálování, rotateAnimation animuje Rotation vlastnost od 0 do 360, více než 4 sekundy. Všimněte si, že animace škálování také používají funkce pro usnadnění. Funkce SpringIn easing způsobí Image počáteční zmenšení před zvětšením a SpringOut easing funkce způsobí Image , že se zmenší, než je její skutečná velikost na konci celé animace.

Mezi objektem Animation , který používá podřízené animace, existuje několik rozdílů a mezi objektem, který:

  • Při použití podřízených animací se dokončené zpětné volání v podřízené animaci označuje, kdy se podřízená položka dokončila, a dokončené zpětné volání předané Commit metodě označuje, kdy byla dokončena celá animace.
  • Pokud použijete podřízené animace, vrácení true z opakování zpětného volání metody Commit nezpůsobí opakování animace, ale animace se bude dál spouštět bez nových hodnot.
  • Pokud do Commit metody zahrnete funkci pro usnadnění a funkce pro usnadnění vrátí hodnotu větší než 1, animace se ukončí. Pokud easing funkce vrátí hodnotu menší než 0, hodnota se uchytne na 0. Chcete-li použít funkci easing, která vrací hodnotu menší než 0 nebo větší než 1, musí být určena v jedné z podřízených animací, nikoli v Commit metodě.

Třída Animation také obsahuje WithConcurrent metody, které lze použít k přidání podřízených animací do nadřazeného Animation objektu. Hodnoty argumentů začátek a dokončení ale nejsou omezeny na hodnotu 0 až 1, ale pouze tato část podřízené animace, která odpovídá rozsahu 0 až 1, bude aktivní. Pokud například WithConcurrent volání metody definuje podřízenou animaci, která cílí na Scale vlastnost od 1 do 6, ale s počáteční a koncové hodnoty -2 a 3, počáteční hodnota -2 odpovídá Scale hodnotě 1 a hodnota dokončení 3 odpovídá Scale hodnotě 6. Vzhledem k tomu, že hodnoty mimo rozsah 0 a 1 nehrají žádnou roli v animaci, Scale vlastnost bude animované pouze od 3 do 6.

Zrušení animace

Aplikace může zrušit animaci s voláním AbortAnimation metody rozšíření, jak je znázorněno v následujícím příkladu kódu:

this.AbortAnimation ("SimpleAnimation");

Všimněte si, že animace jsou jednoznačně identifikovány kombinací vlastníka animace a názvem animace. Proto musí být zadán vlastník a jméno zadané při spuštění animace, aby se animace zrušila. Příklad kódu proto okamžitě zruší animaci, SimpleAnimation která je vlastněná stránkou.

Vytvoření vlastní animace

Zde uvedené příklady zatím ukázaly animace, které lze stejně dosáhnout metodami ve ViewExtensions třídě. Výhodou Animation třídy však je, že má přístup k metodě zpětného volání, která se spustí při změně animované hodnoty. To umožňuje zpětnému volání implementovat jakoukoli požadovanou animaci. Například následující příklad kódu animuje BackgroundColor vlastnost stránky nastavením na Color hodnoty vytvořené Color.FromHsla metodou, přičemž hodnoty odstínu v rozsahu od 0 do 1:

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);

Výsledná animace poskytuje vzhled posouvání pozadí stránky pomocí barev duhy.

Další příklady vytváření složitých animací, včetně animace bezierovy křivky, naleznete v kapitole 22 vytváření mobilních aplikací s Xamarin.Forms.

Vytvoření vlastní metody rozšíření animace

Rozšiřující metody ve ViewExtensions třídě animují vlastnost z její aktuální hodnoty na zadanou hodnotu. Díky tomu je obtížné vytvořit například animační metodu ColorTo , která se dá použít k animaci barvy z jedné hodnoty do druhé, protože:

  • Jedinou Color vlastností definovanou VisualElement třídou je BackgroundColor, což není vždy požadovaná Color vlastnost k animaci.
  • Často je Color.Defaultaktuální hodnota Color vlastnosti , která není skutečnou barvou a kterou nelze použít při interpolačních výpočtech.

Řešením tohoto problému je, ColorTo že metoda cílí na konkrétní Color vlastnost. Místo toho je možné ji zapsat metodou zpětného volání, která předá interpolovanou Color hodnotu zpět volajícímu. Kromě toho bude metoda trvat počáteční a koncové Color argumenty.

Tuto ColorTo metodu lze implementovat jako rozšiřující metodu, která metodu Animate AnimationExtensions ve třídě používá k poskytování jeho funkcí. Důvodem je to, že metodu Animate lze použít k cílení vlastností, které nejsou typu double, jak je znázorněno v následujícím příkladu kódu:

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;
  }
}

Metoda Animate vyžaduje argument transformace , což je metoda zpětného volání. Vstup do tohoto zpětného volání je vždy v rozsahu double od 0 do 1. Proto metoda definuje vlastní transformaciFunc, ColorTo která přijímá double rozsah od 0 do 1 a která vrací Color hodnotu odpovídající této hodnotě. Hodnota Color je vypočítána interpolací R, G, Ba A hodnotami dvou zadaných Color argumentů. Hodnota Color se pak předá metodě zpětného volání pro aplikaci do konkrétní vlastnosti.

Tento přístup umožňuje ColorTo metodě animovat libovolnou Color vlastnost, jak je znázorněno v následujícím příkladu kódu:

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);

V tomto příkladu ColorTo kódu metoda animuje TextColor a BackgroundColor vlastnosti Label, BackgroundColor vlastnost stránky a Color vlastnost .BoxView