Summary of Chapter 22. Animation
Note
This book was published in the spring of 2016, and has not been updated since then. There is much in the book that remains valuable, but some of the material is outdated, and some topics are no longer entirely correct or complete.
You've seen that you can create your own animations using the Xamarin.Forms timer or Task.Delay
, but it is generally easier using the animation facilities provided by Xamarin.Forms. Three classes implement these animations:
ViewExtensions
, the high-level approachAnimation
, more versatile but harderAnimationExtension
, the most versatile, lowest-level approach
Generally, animations target properties that are backed by bindable properties. This is not a requirement but these are the only properties that dynamically react to changes.
There is no XAML interface for these animations, but you can integrate animations into XAML using techniques discussed in Chapter 23. Triggers and Behaviors.
Exploring basic animations
The basic animation functions are extension methods found in the ViewExtensions
class. These methods apply to any object that derives from VisualElement
. The simplest animations target the transforms properties discussed in Chapter 21. Transforms
.
The AnimationTryout demonstrates how the Clicked
event handler for a Button
can call the RotateTo
extension method to spin the button in a circle.
The RotateTo
method changes the Rotation
property of the Button
from 0 to 360 over the course of one-quarter second (by default). If the Button
is tapped again, however, it does nothing because the Rotation
property is already 360 degrees.
Setting the animation duration
The second argument to RotateTo
is a duration in milliseconds. If set to a large value, tapping the Button
during an animation starts a new animation beginning at the current angle.
Relative animations
The RelRotateTo
method performs a relative rotation by adding a specified value to the existing value. This method allows the Button
to be tapped multiple times, and each time increases the Rotation
property by 360 degrees.
Awaiting animations
All the animation methods in ViewExtensions
return Task<bool>
objects. This means that you can define a series of sequential animations using ContinueWith
or await
. The bool
completion return value is false
if the animation finished without interruption or true
if it was cancelled by the CancelAnimation
method, which cancels all animations initiated by the other method in ViewExtensions
that are set on the same element.
Composite animations
You can mix awaited and non-awaited animations to create composite animations. These are the animations in ViewExtensions
that target the TranslationX
, TranslationY
, and Scale
transform properties:
Notice that TranslateTo
potentially affects both the TranslationX
and TranslationY
properties.
Task.WhenAll and Task.WhenAny
It is also possible to manage simultaneous animations using Task.WhenAll
, which signals when multiple tasks have all concluded, and Task.WhenAny
, which signals when the first of several tasks has concluded.
Rotation and anchors
When calling the ScaleTo
, RelScaleTo
, RotateTo
, and RelRotateTo
methods, you can set the AnchorX
and AnchorY
properties to indicate the center of scaling and rotation.
The CircleButton demonstrates this technique by revolving a Button
around the center of the page.
Easing functions
Generally animations are linear from a start value to an end value. Easing functions can cause animations to speed up or slow down over their course. The last optional argument to the animation methods is of type Easing
, a class that defines 11 static read-only fields of type Easing
:
Linear
, the defaultSinIn
,SinOut
, andSinInOut
CubicIn
,CubicOut
, andCubicInOut
BounceIn
andBounceOut
SpringIn
andSpringOut
The In
suffix indicates that the effect is at the beginning of the animation, Out
means at the end, and InOut
means that it's at the beginning and end of the animation.
The BounceButton sample demonstrates the use of easing functions.
Your own easing functions
You can also define you own easing functions by passing a Func<double, double>
to the Easing
constructor. Easing
also defines an implicit conversion from Func<double, double>
to Easing
. The argument to the easing function is always in the range of 0 to 1 as the animation proceeds linearly from beginning to end. The function usually returns a value in the range of 0 to 1, but could be briefly negative or greater than 1 (as is the case with the SpringIn
and SpringOut
functions) or could break the rules if you know what you're doing.
The UneasyScale sample demonstrates a custom easing function, and CustomCubicEase demonstrates another.
The SwingButton sample also demonstrates a custom easing function, and also a technique of changing the AnchorX
and AnchorY
properties within a sequence of rotation animations.
The Xamarin.FormsBook.Toolkit library has a JiggleButton
class that uses a custom easing function to jiggle a button when it's clicked. The JiggleButtonDemo sample demonstrates it.
Entrance animations
One popular type of animation occurs when a page first appears. Such an animation can be started in the OnAppearing
override of the page. For these animations, its best to set up the XAML for how you want the page to appear after the animation, and then initialize and animate the layout from code.
The FadingEntrance sample uses the FadeTo
extension method to fade in the contents of the page.
The SlidingEntrance sample uses the TranslateTo
extension method to slide in the contents of the page from the sides.
The SwingingEntrance sample uses the RotateYTo
extension method to animate the RotationY
property. A RotateXTo
method is also available.
Forever animations
At the other extreme, "forever" animations run until the program is terminated. These are generally intended for demonstration purposes.
The FadingTextAnimation sample uses FadeTo
animation to fade two pieces of text in and out.
PalindromeAnimation displays a palindrome, and then sequentially rotates the individual letters by 180 degrees so they're all upside-down. Then the entire string is flipped 180 degrees to read the same as the original string.
The CopterAnimation sample rotates a simple BoxView
helicopter while revolving it around the center of the screen.
RotatingSpokes revolves BoxView
spokes around the center of the screen, and then rotates each spoke itself to create interesting patterns:
However, progressively increasing the Rotation
property of an element might not work in the long term, as the RotationBreakdown sample demonstrates.
The SpinningImage sample uses RotateTo
, RotateXTo
, and RotateYTo
to make it seem as if a bitmap is rotating in 3D space.
Animating the bounds property
The only extension method in ViewExtensions
not yet demonstrated is LayoutTo
, which effectively animates the read-only Bounds
property by calling the Layout
method. This method is normally called by Layout
derivatives as will be discussed in Chapter 26. CustomLayouts.
The LayoutTo
method should be restricted to special purposes. The BouncingBox program uses it to compress and expand a BoxView
as it bounces off the sides of a page.
The XamagonXuzzle sample uses LayoutTo
to move tiles in an implementation of the classic 15-16 puzzle that displays a scrambled image rather than numbered tiles:
Your own awaitable animations
The TryAwaitableAnimation sample creates an awaitable animation. The crucial class that can return a Task
object from the method and signal when the animation is completed is TaskCompletionSource
.
Deeper into animations
The Xamarin.Forms animation system can be a little confusing. In addition to the Easing
class, the animation system comprises the ViewExtensions
, Animation
, and AnimationExtension
classes.
ViewExtensions class
You've already seen ViewExtensions
. It defines nine methods that return Task<bool>
and CancelAnimations
. Seven of the nine methods target transform properties. The other two are FadeTo
, which targets the Opacity
property, and LayoutTo
, which calls the Layout
method.
Animation class
The Animation
class has a constructor with five arguments to define callback and finished methods, and parameters of the animation.
Child animations can be added with Add
, Insert
, WithConcurrent
, and overload of WithConcurrent
.
The animation object is then started with a call to the Commit
method.
AnimationExtensions class
The AnimationExtensions
class contains mostly extension methods. There are several versions of an Animate
method and the generic Animate
method is so versatile that it's really the only animation function you need.
Working with the Animation class
The ConcurrentAnimations sample demonstrates the Animation
class with several different animations.
Child animations
The ConcurrentAnimations sample also demonstrates child animations, which make use of the (very similar) Add
and Insert
methods.
Beyond the high-level animation methods
The ConcurrentAnimations sample also demonstrates how to perform animations that go beyond the properties targeted by the ViewExtensions
methods. In one example, a series of periods get longer; in another example, a BackgroundColor
property is animated.
More of your own awaitable methods
The TranslateTo
method of ViewExtensions
doesn't work with the Easing.SpringOut
function. It stops when the easing output gets above 1.
The Xamarin.FormsBook.Toolkit library contains a MoreViewExtensions
class with TranslateXTo
and TranslateYTo
extension methods that don't have this problem, as well as CancelTranslateXTo
and CancelTranslateYTo
methods for cancelling those animations.
The SpringSlidingEntrance demonstrates the TranslateXTo
method.
The MoreExtensions
class also contains a TranslateXYTo
extension method that combines X and Y translation, and a CancelTranslateXYTo
method.
Implementing a Bezier animation
It is also possible to develop an animation that moves an element along the path of a Bezier spline. The Xamarin.FormsBook.Toolkit library contains a BezierSpline
structure that encapsulates a Bezier spline and a BezierTangent
enumeration to control orientation.
The MoreViewExtensions
class contains a
BezierPathTo
extension method
and a CancelBezierPathTo
method.
The BezierLoop sample demonstrates animating an element along a Beizer path.
Working with AnimationExtensions
One type of animation missing from the standard collection is a color animation. The problem is that there is no right way to interpolate between two Color
values. It's possible to interpolate the individual RGB values, but just as valid is interpolating the HSL values.
For this reason, the MoreViewExtensions
class in the Xamarin.FormsBook.Toolkit library contains two Color
animation methods:
RgbColorAnimation
and
HslColorAnimation
. (There are also two cancellation methods:
CancelRgbColorAnimation
and
CancelHslColorAnimation
).
Both methods make use of ColorAnimation
, which performs the animation by calling the extensive generic Animate
method in AnimationExtensions
.
The ColorAnimations sample demonstrates using these two types of color animations.
Structuring your animations
It's sometimes useful to express animations in XAML and use them in conjunction with MVVM. This is covered in the next chapter, Chapter 23. Triggers and Behaviors.