Three dots, blinking and pulsating sequentially made with pure Xamarin.Forms Animations! (no third party elements, heck not even any images used)
A little fun experimental-implementation I did a while back, actually based on something I did long time ago for an office project, but then figured out I could make it much better in a later time, so thought of working on it and putting it out there.
So basically we needed to have a Loading screen or Activity indicator screen with cool three dots animating sequentially, instead of using a GIF, I wanted to do this purely from Xamarin.Forms without any use of a 3rd party component, not even any image or icon.
Yes, I ended up hacking my way to get this done!
Here’s that interesting journey unfolding…
Xamarin.Forms.Animations is awesome!
This is something I need to get out of my chest. No one would actual believe this, but there’s so many awesome stuff you could do with the built in Animations of Xamarin.Forms right out of the box.
Surprisingly it’s super simple as well!
Sneak Peak!
So here’s what I’ve built and what you’re gonna get! 😉
TADAAA! pretty cool eh!
Let’s get started…
So before I get started, the requirement here is to build a reusable “Control” that we can embed into a ContentPage that we would be using as a “Loading Screen” or an Activity Indicator screen as some might call it. So this is going to be a separate reusable View which you can embed anywhere you want to and use it right away, which will be independent of it own, yes even the whole Animation sequence is self sustained by itself. 😉 Oh yeah! Cool stuff ahead! 😀
Building the UI..
First of all let’s go on create a ContentView control, let’s name it, AnimatingDotsControl!
What we need here is just simple “three dots”, but like I said in the beginning I don’t want to use any third party components or even external Image to emulate “a dot” element.
So what am I going to use for “a dot”? Xamarin.Forms.Frame! MIND BLOWN!
Let the Hack-be-unfolded!
Right on fellas, just another Xamarin.Forms hack of my own, Frame View has this awesome property called CornerRadius, which we are going to use for our advantage here, when its sufficiently set properly to the proportion of the width and height of it, voila! you render a circle or a dot in this case.
So let’s go on add three Frame elements horizontally inside a Grid view. And also to emulate the blinking, “on” and “off” state of a dot, we need to maintain two Frame elements to represent one dot each. We’re going stack them on top of each other, so when the first one goes to off state the second one in the background will come to visibility and emulate the off state. So for the ease of use let’s call our tiny little Frame elements, Dot1, Dot2 and Dot3 and lay them out nicely as we discussed.
<?xml version="1.0" encoding="UTF-8" ?> <ContentView x:Class="XFAnimatingDotsControl.AnimatingDotsControl" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"> <ContentView.Resources> <ResourceDictionary> <Style x:Key="AnimatingDotsStyle" TargetType="Frame"> <Setter Property="Padding" Value="5" /> <Setter Property="BackgroundColor" Value="White" /> <Setter Property="CornerRadius" Value="6" /> <Setter Property="HasShadow" Value="False" /> <Setter Property="HorizontalOptions" Value="Center" /> <Setter Property="VerticalOptions" Value="Center" /> <Setter Property="HeightRequest" Value="4" /> <Setter Property="WidthRequest" Value="4" /> </Style> <Style x:Key="BackgroundDotsStyle" BasedOn="{StaticResource AnimatingDotsStyle}" TargetType="Frame"> <Setter Property="BackgroundColor" Value="DimGray" /> </Style> </ResourceDictionary> </ContentView.Resources> <ContentView.Content> <Grid ColumnSpacing="2" HorizontalOptions="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> </Grid.ColumnDefinitions> <!-- Background Dots --> <Frame Grid.Column="0" Style="{StaticResource BackgroundDotsStyle}" /> <Frame Grid.Column="1" Style="{StaticResource BackgroundDotsStyle}" /> <Frame Grid.Column="2" Style="{StaticResource BackgroundDotsStyle}" /> <!-- Animating Dots --> <Frame x:Name="Dot1" Grid.Column="0" Style="{StaticResource AnimatingDotsStyle}" /> <Frame x:Name="Dot2" Grid.Column="1" Style="{StaticResource AnimatingDotsStyle}" /> <Frame x:Name="Dot3" Grid.Column="2" Style="{StaticResource AnimatingDotsStyle}" /> </Grid> </ContentView.Content> </ContentView>
There you go. Just like we discussed we have our UI set up in a reusable ContentView control, just like we discussed above. Oh and don’t be worried by the use of Styles, I just like to make my XAML look neat and clean. 😉
Building the Animation!
Here’s the golden part of the whole post, the actual Animation magic brewed purely with Xamarin.Forms! Most people are aware only of the Xamarin.Forms Animation Extension methods, the typical FadeTo(), ScaleTo(), etc whatnot. But that’s just the tip of the ice berg I tell you! 😀
Here’s a little heads up if you’re not aware: Xamarin.Forms.Animation!
The whole Xamarin.Forms.Animation class itself has many more awesomeness possibilities, it allows us to create our own Animation sequences. Oh yeah! how cool is that eh!
These custom Animation objects can be attached to any Xamain.Forms.View and make them dance like whatever the ways we want, as in to animate any of its properties as we wish. They can sequentially change value of any property for any given period of time, even repeatedly. That is the whole bread and butter of this implementation. The Animation object constructor allows us to execute a sequential loop of an action with any given value, incremented or decremented, with the Easing properties, and finishing it with another action. Let’s use this for our advantage…
new Animation(alpha => Dot1.Opacity = alpha, 1, 0, Easing.CubicOut, () => Dot1.FadeTo(1))
So we’re going to using the Opacity property of our Frame view, and change its value from 1 to 0 in a loop, with an CubitOut Easing behavior, and reversing it back in the end of the execution, thus creating the blinking effect! 😀
And here’s the coolest part, you can actually attach an Animation object into another Animation object, and so on, so that you can execute a bunch animations sequentially across multiple views. Animation.Add() method gives you this awesomeness, where as you can define a starting point of the timeline and ending point for that specific animation object, in the whole animation sequence. So given our three animating elements, let’s break our timeline into 3 time chunks, giving each element a time span of 0.33 milliseconds.
var pulseAnimation1 = new Animation(); pulseAnimation1.Add(0, 0.33, new Animation(alpha => Dot1.Opacity = alpha, 1, 0, Easing.CubicOut, () => Dot1.FadeTo(1)));
So using that we’re going to animate three of our “dot views”, Dot1, Dot2 and Dot3, by attaching their own animation objects to a single Animation. We’re going to repeat the same above Add() call to Dot2 and Dot3 in the next step.
Before I get into the full animation code, the way we actually run this animation sequence is by calling the Animation.Commit() method, passing the parent View and some useful bits we could use to customize the animation sequence altogether.
private void RunAnimations() { var pulseAnimation1 = new Animation(); pulseAnimation1.Add(0, 0.33, new Animation(alpha => Dot1.Opacity = alpha, 1, 0, Easing.CubicOut, () => Dot1.FadeTo(1))); pulseAnimation1.Add(0.33, 0.66, new Animation(alpha => Dot2.Opacity = alpha, 1, 0, Easing.CubicOut, () => Dot2.FadeTo(1))); pulseAnimation1.Add(0.66, 0.99, new Animation(alpha => Dot3.Opacity = alpha, 1, 0, Easing.CubicOut, () => Dot3.FadeTo(1))); pulseAnimation1.Commit(this, "loadingIndicatorPulseAnimation", 10, 1100, null, null, () => true); }
So you can see how we have allocated each animation chunk 0.33 milliseconds and most importantly at the end the Commit() call, passing in the current view we’re attaching this animation to, the time in milliseconds between frames, the allocated time in milliseconds for the whole animation sequence, and the null for easing and finishing action, since I’ve already defined them in the child animations themselves, and the last parameter, enabling the repeating functionality. So the animation will keep running forever as long as its active.
Now we have a self sustaining animation that runs repeatedly, but what if we want to stop it and discard it, in the case of the disposing or removing the View? that’s where AbortAnimation() call comes in.
// abort the animation on element disposing this.AbortAnimation("loadingIndicatorPulseAnimation");
Remember we gave a little name to our animation? yeah that’s what we’re going to use and such a simple call the animation will stop and discard itself.
A true self sustaining Animation Control!
Alright! So now we have our full Animation implemented, the next thing we need to do is to make sure its self sustaining, since we’re going to use it inside an independent control.
So whenever the Control is attached to the UI or made visible, we need to make sure to start the Animation and when the Control is removed from UI or disposed, then we should stop the animation and dispose itself.
In order to do this we need to look into the life cycle of a Xamarin.Forms.View!
Let the Hack-be-unfolded!
So this is a little hacking around I came up with myself after overriding a bunch of methods and debugging the run time of Xamarin.Forms, where as when any given View gets attached to a parent or becomes visible, there’s an internal property that gets fired, which is called “Renderer”, even at the time of View goes out of visibility or removed from parent, the same property will get fired. I’m presuming this to a call to the native renderer of the View itself back and forth at runtime. I’m going to use this as Entry and Exit points for managing our Animation.
We shall override the OnPropertyChanged event of our ContentView and watch out for the “Renderer” property change, maintain a little flag to mark down our Animation started and ended state.
public partial class AnimatingDotsControl : ContentView { public AnimatingDotsControl() { InitializeComponent(); } private bool _animationStarted; protected override void OnPropertyChanged( [CallerMemberName] string propertyName = null) { base.OnPropertyChanged(propertyName); if (propertyName == "Renderer") { if (!_animationStarted) { // start the animation on element rendering _animationStarted = true; RunAnimations(); } else { // abort the animation on element disposing this.AbortAnimation( "loadingIndicatorPulseAnimation"); } } } private void RunAnimations() { ... } }
There you go, now we have a fully self sustaining animation which will start on its own when the Control is attached to a parent or made visible, and then dispose itself when the Control is removed from parent or made out of visibility! 😀
Let’s consume it!
No more waiting, let’s consume this bad boy!
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="XFAnimatingDotsControl.LoadingScreen" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:xfAnimatingDotsControl="clr-namespace:XFAnimatingDotsControl;assembly=XFAnimatingDotsControl" BackgroundColor="Gray"> <Frame BackgroundColor="Transparent" HasShadow="False" HorizontalOptions="Center" OutlineColor="Transparent" VerticalOptions="Center"> <StackLayout BackgroundColor="Transparent" Orientation="Vertical"> <Label FontAttributes="Bold" FontSize="23" HorizontalOptions="Center" HorizontalTextAlignment="Center" Text="Loading" TextColor="White" /> <!-- Embedding our Animating Dots Control --> <xfAnimatingDotsControl: AnimatingDotsControl HorizontalOptions="Center" /> </StackLayout> </Frame> </ContentPage>
There we have embeded our own AnimatingDotsControl into a ContentPage that we would be using as a “Loading Screen” or an Activity Indicator screen as some might call it. Then you could use that page as a Modal Page and make it visible or discard whenever you wish so. 😉
You can attach our little awesome Animation dots control anywhere as you wish and it will work out nicely like a charm, while behaving and maintaining itself.
That’s our bad boy in action on iOS and Android! 😀
Github it if yo lazy!
So all of this is hosted on my git repo: https://github.com/XFAnimatingDotsControl
Feel free to grab your copy if you’re too lazy to DIY! 😛
Imagination and creativity is your weapon against the odds, keep on pushing the limits and hacking your way through my fellow developer! That’s what makes us the “Developers”, we build cool stuff yol!
That’s it for today.
Cheers all! 😀 Share the love!