Benutzerdefinierte Animationen in Xamarin.Forms
Die Animation-Klasse ist der Baustein aller Xamarin.Forms Animationen, wobei die Erweiterungsmethoden in der ViewExtensions-Klasse ein oder mehrere Animationsobjekte erstellen. In diesem Artikel wird veranschaulicht, wie Sie mithilfe der Animationsklasse Animationen erstellen und abbrechen, mehrere Animationen synchronisieren und benutzerdefinierte Animationen erstellen, die Eigenschaften animieren, die nicht von den vorhandenen Animationsmethoden animiert werden.
Bei der Erstellung eines Animation
-Objekts muss eine Reihe von Parametern angegeben werden, darunter Start- und Endwerte der zu animierenden Eigenschaft und ein Rückruf, der den Wert der Eigenschaft ändert. Ein Animation
-Objekt kann auch eine Sammlung von untergeordneten Animationen verwalten, die ausgeführt und synchronisiert werden können. Weitere Informationen finden Sie unter untergeordnete Animationen.
Die Ausführung einer mit der Klasse Animation
erstellten Animation, die auch untergeordnete Animationen enthalten kann, wird durch den Aufruf der Methode Commit
erreicht. Diese Methode gibt die Dauer der Animation und unter anderem einen Rückruf an, der steuert, ob die Animation wiederholt werden soll.
Darüber hinaus verfügt die Animation
Klasse über eine IsEnabled
Eigenschaft, die untersucht werden kann, um festzustellen, ob Animationen vom Betriebssystem deaktiviert wurden, z. B. beim Aktivieren des Energiesparmodus.
Erstellen einer Animation
Bei der Erstellung eines Animation
-Objekts sind in der Regel mindestens drei Parameter erforderlich, wie das folgende Codebeispiel zeigt:
var animation = new Animation (v => image.Scale = v, 1, 2);
Dieser Code definiert eine Animation der Scale
Eigenschaft einer Image
Instanz von einem Wert von 1 bis zu einem Wert von 2. Der animierte Wert, der von Xamarin.Formsdiesem abgeleitet wird, wird an den als erstes Argument angegebenen Rückruf übergeben, in dem er verwendet wird, um den Wert der Scale
Eigenschaft zu ändern.
Die Animation wird mit einem Aufruf der Commit
Methode gestartet, wie im folgenden Codebeispiel veranschaulicht:
animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);
Beachten Sie, dass die Commit
Methode kein Objekt zurückgibt Task
. Stattdessen werden die Benachrichtigungen über Callback-Methoden bereitgestellt.
Die folgenden Argumente werden in der Methode Commit
angegeben:
- Das erste Argument (Besitzer) identifiziert den Besitzer der Animation. Dies kann das visuelle Element sein, auf das die Animation angewendet wird, oder ein anderes visuelles Element, wie etwa die Seite.
- Das zweite Argument (Name) identifiziert die Animation mit einem Namen. Der Name wird mit dem Eigentümer kombiniert, um die Animation eindeutig zu identifizieren. Anhand dieser eindeutigen Bezeichnung kann dann festgestellt werden, ob die Animation läuft (
AnimationIsRunning
), oder sie kann abgebrochen werden (AbortAnimation
). - Das dritte Argument (Rate) gibt die Anzahl von Millisekunden zwischen jedem Aufruf der im
Animation
Konstruktor definierten Rückrufmethode an. - Das vierte Argument (Länge) gibt die Dauer der Animation in Millisekunden an.
- Das fünfte Argument (Beschleunigung) definiert die Beschleunigungsfunktion, die in der Animation verwendet werden soll. Alternativ kann die Beschleunigungsfunktion auch als Argument für den
Animation
-Konstruktor angegeben werden. Weitere Informationen zu Beschleunigungsfunktionen finden Sie unter Beschleunigungsfunktionen. - Das sechste Argument (fertig) ist ein Rückruf, der ausgeführt wird, wenn die Animation abgeschlossen ist. Dieser Rückruf nimmt zwei Argumente entgegen, wobei das erste Argument einen Endwert angibt und das zweite Argument ein
bool
ist, das auftrue
gesetzt wird, wenn die Animation abgebrochen wurde. Alternativ kann der fertige Rückruf als Argument für denAnimation
Konstruktor angegeben werden. Bei einer einzelnen Animation werden jedoch, wenn fertige Rückrufe sowohl im Konstruktor als auchAnimation
in derCommit
Methode angegeben sind, nur der in derCommit
Methode angegebene Rückruf ausgeführt. - Das siebte Argument (Wiederholen) ist ein Rückruf, der die Wiederholung der Animation zulässt. Es wird am Ende der Animation aufgerufen, und die Rückgabe von
true
zeigt an, dass die Animation wiederholt werden soll.
Der Gesamteffekt besteht darin, eine Animation zu erstellen, die die Scale
Eigenschaft einer Image
von 1 auf 2, über 2 Sekunden (2000 Millisekunden) mit der Linear
Beschleunigungsfunktion erhöht. Jedes Mal, wenn die Animation abgeschlossen ist, wird ihre Scale
-Eigenschaft auf 1 zurückgesetzt, und die Animation wird wiederholt.
Hinweis
Gleichzeitige Animationen, die unabhängig voneinander ablaufen, können erstellt werden, indem man für jede Animation ein Animation
-Objekt erstellt und dann die Commit
-Methode für jede Animation aufruft.
Untergeordnete Animationen
Die Animation
Klasse unterstützt auch untergeordnete Animationen, bei denen ein Objekt erstellt Animation
wird, dem andere Animation
Objekte hinzugefügt werden. So kann eine Reihe von Animationen ausgeführt und synchronisiert werden. Das folgende Codebeispiel veranschaulicht die Erstellung und Ausführung von untergeordneten Animationen:
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));
Alternativ kann das Codebeispiel präziser geschrieben werden, wie im folgenden Codebeispiel gezeigt:
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));
In beiden Codebeispielen wird ein übergeordnetes Animation
Objekt erstellt, dem dann zusätzliche Animation
Objekte hinzugefügt werden. Die ersten beiden Argumente der Methode Add
geben an, wann die untergeordnete Animation beginnen und enden soll. Die Werte der Argumente müssen zwischen 0 und 1 liegen und stellen den relativen Zeitraum innerhalb der übergeordneten Animation dar, in dem die angegebene untergeordnete Animation aktiv sein wird. In diesem Beispiel ist scaleUpAnimation
also für die erste Hälfte der Animation aktiv, scaleDownAnimation
für die zweite Hälfte der Animation und rotateAnimation
für die gesamte Dauer.
Der Gesamteffekt besteht darin, dass die Animation über 4 Sekunden (4000 Millisekunden) erfolgt. Die scaleUpAnimation
animiert die Scale
Eigenschaft von 1 auf 2, über 2 Sekunden. Die scaleDownAnimation
animiert dann die Scale
-Eigenschaft von 2 auf 1, über 2 Sekunden. Während beide Skalierungsanimationen ablaufen, animiert die rotateAnimation
die Rotation
-Eigenschaft über 4 Sekunden von 0 bis 360. Beachten Sie, dass die Skalierungsanimationen auch Beschleunigungsfunktionen verwenden. Die SpringIn
Beschleunigungsfunktion bewirkt, dass die Image
Beschleunigungsfunktion zunächst verkleinern wird, bevor sie größer wird, und die SpringOut
Beschleunigungsfunktion bewirkt, dass die Image
tatsächliche Größe am Ende der vollständigen Animation kleiner wird.
Es gibt eine Reihe von Unterschieden zwischen einem Animation
-Objekt, das untergeordnete Animationen verwendet, und einem, das dies nicht tut:
- Bei Verwendung untergeordneter Animationen gibt der fertige Rückruf für eine untergeordnete Animation an, wann das untergeordnete Element abgeschlossen ist, und der an die
Commit
Methode übergebene Rückruf gibt an, wann die gesamte Animation abgeschlossen ist. - Wenn Sie untergeordnete Animationen verwenden, führt die Rückgabe des Wiederholten Rückrufs
true
für dieCommit
Methode nicht dazu, dass die Animation wiederholt wird, aber die Animation wird weiterhin ohne neue Werte ausgeführt. - Wenn eine Beschleunigungsfunktion in die
Commit
-Methode eingebunden wird und die Lockerungsfunktion einen Wert größer als 1 zurückgibt, wird die Animation abgebrochen. Wenn die Beschleunigungsfunktion einen Wert kleiner als 0 zurückgibt, wird der Wert auf 0 geklemmt. Um eine Beschleunigungsfunktion zu verwenden, die einen Wert kleiner als 0 oder größer als 1 zurückgibt, muss sie in einer der untergeordneten Animationen und nicht in der MethodeCommit
angegeben werden.
Die Animation
-Klasse enthält auch WithConcurrent
-Methoden, die verwendet werden können, um einem übergeordneten Animation
-Objekt untergeordnete Animationen hinzuzufügen. Die Anfangs - und Endargumentwerte sind jedoch nicht auf 0 bis 1 beschränkt, sondern nur der Teil der untergeordneten Animation, der einem Bereich von 0 bis 1 entspricht, ist aktiv. Wenn ein WithConcurrent
Methodenaufruf z. B. eine untergeordnete Animation definiert, die auf eine Scale
Eigenschaft von 1 bis 6 ausgerichtet ist, aber mit den Anfangs- und Endwerten von -2 und 3 entspricht der Anfangswert von -2 einem Scale
Wert von 1, und der Endwert von 3 entspricht einem Scale
Wert von 6. Da Werte außerhalb des Bereichs von 0 und 1 bei einer Animation keine Rolle spielen, wird die Eigenschaft Scale
nur von 3 bis 6 animiert.
Abbrechen einer Animation
Eine Anwendung kann eine Animation mit einem Aufruf der AbortAnimation
Erweiterungsmethode abbrechen, wie im folgenden Codebeispiel veranschaulicht:
this.AbortAnimation ("SimpleAnimation");
Beachten Sie, dass Animationen durch eine Kombination des Animationsbesitzers und den Animationsnamen eindeutig identifiziert werden. Daher muss der Beim Ausführen der Animation angegebene Besitzer und Name angegeben werden, um die Animation abzubrechen. Daher wird die Animation SimpleAnimation
, die im Besitz der Seite ist, sofort abgebrochen.
Erstellen einer benutzerdefinierten Animation
Die bisher gezeigten Beispiele haben Animationen gezeigt, die auch mit den Methoden der Klasse ViewExtensions
erreicht werden können. Der Vorteil der Klasse Animation
besteht jedoch darin, dass sie Zugriff auf die Callback-Methode hat, die ausgeführt wird, wenn sich der animierte Wert ändert. Dadurch kann der Callback jede gewünschte Animation implementieren. Das folgende Codebeispiel animiert beispielsweise die BackgroundColor
-Eigenschaft einer Seite, indem sie auf Color
-Werte gesetzt wird, die mit der Color.FromHsla
-Methode erstellt wurden, wobei die Farbtonwerte von 0 bis 1 reichen:
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);
Die daraus resultierende Animation erweckt den Anschein, dass der Seitenhintergrund durch die Farben des Regenbogens fortschreitet.
Weitere Beispiele zum Erstellen komplexer Animationen, einschließlich einer Bézierkurvenanimation, finden Sie in Kapitel 22 der Erstellung mobiler Apps mit Xamarin.Forms.
Erstellen einer benutzerdefinierten Erweiterungsmethode für Animationen
Die Erweiterungsmethoden in der Klasse ViewExtensions
animieren eine Eigenschaft von ihrem aktuellen Wert zu einem bestimmten Wert. Dies macht es schwierig, beispielsweise eine ColorTo
Animationsmethode zu erstellen, die zum Animieren einer Farbe von einem Wert zu einem anderen verwendet werden kann, da:
- Die einzige
Color
von derVisualElement
Klasse definierte Eigenschaft istBackgroundColor
, was nicht immer die gewünschteColor
Eigenschaft ist, die animiert werden soll. - Häufig ist
Color.Default
der aktuelle Wert einerColor
Eigenschaft eine echte Farbe, die in Interpolationsberechnungen nicht verwendet werden kann.
Die Lösung für dieses Problem besteht darin, dass die ColorTo
-Methode nicht auf eine bestimmte Color
-Eigenschaft abzielt. Stattdessen kann sie mit einer Rückruf-Methode geschrieben werden, die den interpolierten Color
-Wert an den Aufrufer zurückgibt. Darüber hinaus erhält die Methode Start- und Endargumente Color
.
Die ColorTo
-Methode kann als Erweiterungsmethode implementiert werden, die die Animate
-Methode in der AnimationExtensions
-Klasse verwendet, um ihre Funktionalität bereitzustellen. Dies liegt daran, dass die Animate
-Methode verwendet werden kann, um auf Eigenschaften zu zielen, die nicht vom Typ double
sind, wie im folgenden Codebeispiel gezeigt wird:
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;
}
}
Für die Animate
Methode ist ein Transformationsargument erforderlich, bei dem es sich um eine Rückrufmethode handelt. Die Eingabe für diesen Rückruf ist immer ein double
im Bereich von 0 bis 1. Daher definiert die ColorTo
Methode eine eigene Transformation Func
, die einen double
Bereich von 0 bis 1 akzeptiert und einen Color
Wert zurückgibt, der diesem Wert entspricht. Der Color
-Wert wird durch Interpolation der R
-, G
-, B
- und A
-Werte der beiden gelieferten Color
-Argumente berechnet. Der Color
Wert wird dann an die Rückrufmethode für die Anwendung an eine bestimmte Eigenschaft übergeben.
Mit diesem Ansatz kann die ColorTo
Methode jede Color
Eigenschaft animieren, wie im folgenden Codebeispiel gezeigt:
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);
In diesem Codebeispiel animiert die Methode ColorTo
die Eigenschaften TextColor
und BackgroundColor
eines Label
, die Eigenschaft BackgroundColor
einer Seite und die Eigenschaft Color
eines BoxView
.