Home My Book Contact

Skype style animations with Xamarin.Forms

I want to try and recreate some of the animations that the new Skype of iOS app has using Xamarin.Forms. If you are not familiar with what I am talking about, take a quick look at Brian Lovin's Design Details blog on Skype.

A quick search brings up this post by Arkadiusz Holko. Arkadiusz put his solution on GitHub, so I decided to see what I could learn from that and port it to a Xamarin.Forms project. Here is what I ended up with:

Animation 3 Animation 3 Android

I'm hoping this can be used for a custom alert sheet style view, just like Skype uses.

Animation

Xamarin.Forms already has built in routines to animate position changes. LayoutTo(position, duration, Easing) gives me everything I need to animate my views around the screen.

myView.LayoutTo(position, 500, Easing.SpringOut);  

With just these pieces in place, I was able to get something basic up and running that looks similar to what Arkadiusz has done.

Animation 1

Easing

To change the animation curve, we can provide an easing function. The curve that Easing.SpringOut provides is pretty close to what I wanted. Unfortunately, there is no way to customize the coefficients it uses. So instead, I used a custom easing method so I could change the elasticity:

new Easing((x) => {  
    return ((x - 1) * (x - 1) * (( sidecoeff + 1 ) * (x - 1) + sidecoeff) + 1);
})

see here for the original BackEaseOut method used. Simplification explained here

And the result after some tweaking:

Animation 2

Drawing

I don't currently know of an API to do this that is built into Xamarin.Forms. Another quick search brings me to Christian Falch's NControl library. This gives you the NControlView class which provides cross-platform drawing APIs. Here is what I ended up with:

public override void Draw (NGraphics.ICanvas canvas, NGraphics.Rect rect)  
{
    base.Draw (canvas, rect);

    double yOffset = 20;
    double width = rect.Width;
    double height = rect.Height;

    var points = new PathOp[] {
        new MoveTo(0, yOffset - delta),
        new CurveTo(new NGraphics.Point(width / 2, yOffset + delta),
        new NGraphics.Point(width / 2, yOffset + delta), 
        new NGraphics.Point(width, yOffset - delta)),
        new LineTo(width, height),
        new LineTo(0, height)
    };

    canvas.DrawPath(points, null, new SolidBrush(new NGraphics.Color(0, 0.722, 1, 1)));
}

Arkadiusz's post talks about using CADisplayLink to get a calback for each frame of the animation where the curve can be updated. I did not find a great place to do something similar in shared code, so I put it in the custom easing method which I figured is called similarly.

new Easing((x) => {  
    UpdateCurve();
    return ((x - 1) * (x - 1) * (( sidecoeff + 1 ) * (x - 1) + sidecoeff) + 1);
})

The UpdateCurve() method simply calculates the delta of the side and center helper views and calls Invalidate() on the actual NControlView being drawn. This means that each time the easing method is called, the view will be invalidated and cause the curve to be updated each step of the animation. The end result is pretty good.

Animation 3 Animation 3 Android

I'm hoping I can turn this into a control and fine tune the animation to be even closer to what Skype has done. If you have not already, I encourage you to stop by Arkadiusz's GitHub page and take a look at the work he's done.