Silverlight 3D flip animation
April 25, 2008 @ 12:20 am in Microsoft, Silverlight
Up until now I have not had an opportunity to create any Silverlight procedural animations that were more complicated then positioning an object with some simple easing. I thought it would be fun to attempt to duplicate one of the transitions used on the iPhone. While making a phone call, if you choose to display the keypad there is a cool 3D flip that occurs. Here is a quick video of the transition. [[VIDEO]] In hopes not to reinvent the wheel, I embarked on an endless search of the Internet for anything resembling a flip. After some quality time on Google, I stumbled upon a great Flash site called reflektions by Paul Ortchanian. This site has a ton of Flash examples that highlight 2D and 3D effects done in flash. Those of us new to interactive development can learn a ton from the techniques Flash and Flex developers have used for years. To get started I created a simple page that contained two Grid controls, one for the front of the flip and one for the back. Both were placed inside of a single canvas named “screens”.
The guts of this effect has been encapsulated in a method called “AnimateFlip”. The result of this method is a DobuleAnimation with approximately 48 descreate keys frames.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | private TimeSpan AnimateFlip(Storyboard sb, ScaleTransform scale,
out TimeSpan tsLastFrame)
{
double speed = 4;
double flipRotation = 0;
double flipped = 2;
tsLastFrame = new TimeSpan();
TimeSpan tsSideFlipped = new TimeSpan();
int frames = 1;
DoubleAnimationUsingKeyFrames daX =
new DoubleAnimationUsingKeyFrames();
tsLastFrame = new TimeSpan();
while (flipRotation != flipped * 180)
{
flipRotation += speed;
double flipRadian = flipRotation * (Math.PI / 180);
double size = Math.Cos(flipRadian);
double scalar = (1 / (1 / size));
DiscreteDoubleKeyFrame ddkfX = new DiscreteDoubleKeyFrame();
ddkfX.Value = (size * scalar) ;
tsLastFrame = TimeSpan.FromMilliseconds(frames * 7);
//the first time we flip to negative capture the
//tsLastFrame so we know when we will need to
//visualize the flip side
flipped = (size < 0) ? +1 : +0;
if (flipped == 1 && tsSideFlipped.Ticks == 0)
{
tsSideFlipped = tsLastFrame;
}
ddkfX.KeyTime = KeyTime.FromTimeSpan(tsLastFrame);
//add the DiscreteDoubleKeyFrame to the
//DoubleAnimationUsingKeyFrames
daX.KeyFrames.Add(ddkfX);
flipRotation %= 360;
frames++;
}
Storyboard.SetTarget(daX, scale);
Storyboard.SetTargetProperty(daX, "ScaleX");
sb.Children.Add(daX);
VisualizeSide(sb, tsSideFlipped, 0, TimeSpan.FromMilliseconds
((tsSideFlipped.Milliseconds + 100)),
back.Opacity, this.back);
VisualizeSide(sb, TimeSpan.FromMilliseconds((
tsSideFlipped.Milliseconds - 100)), front.Opacity,
tsSideFlipped, 0, this.front);
back.Opacity = 0;
return tsLastFrame;
} |
At the very bottom of the above method their is two calls to “VisualizeSide”. This method is responsible for visualizing the second side when the screen has rotated 180 degrees (Flipped).
My animation is by no means exact, but a pretty good first attempt. If you watch the video very slowly you might notice that on the iPhones rotation it looks like it rotates in perspective. I would love to add this, but am at a lost
Code: ScreenFlip.zip
/p>
Tagged as 

May 3rd, 2008 at 6:42 am
Hi Joel,
Thank you for sharing this – it’s very nice!
David
May 15th, 2008 at 11:36 pm
[...] a few weeks ago I posted an example of how to create a 3D flip animation similar to the effect seen on an iPhone. Today I will build upon that procedural animation and [...]
June 23rd, 2008 at 11:43 pm
Great Post!
I do have a question. Would it be easy to make the Back grid larger then the front Grid? So that if you click on the front youll get more detail on the back side and still make a good 3d animation?
July 1st, 2008 at 12:03 pm
I spun this off as a class with a static methods so I could reuse it in many places. Here’s the code for anyone that wants to save some time.
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ScreenFlip
{
public class FlipStoryboardCreator
{
public static void Create(UIElement front, UIElement back, out Storyboard sb, out ScaleTransform scale, out TimeSpan tsLastFrame)
{
double speed = 4;
double flipRotation = 0;
double flipped = 2;
sb = new Storyboard();
scale = new ScaleTransform();
tsLastFrame = new TimeSpan();
TimeSpan tsSideFlipped = new TimeSpan();
int frames = 1;
DoubleAnimationUsingKeyFrames daX = new DoubleAnimationUsingKeyFrames();
tsLastFrame = new TimeSpan();
while (flipRotation != flipped * 180)
{
flipRotation += speed;
double flipRadian = flipRotation * (Math.PI / 180);
double size = Math.Cos(flipRadian);
double scalar = (1 / (1 / size));
DiscreteDoubleKeyFrame ddkfX = new DiscreteDoubleKeyFrame();
ddkfX.Value = (size * scalar);
tsLastFrame = TimeSpan.FromMilliseconds(frames * 7);
//the first time we flip to negative capture the tsLastFrame so we know when we will need to
//visualize the flip side
flipped = (size < 0) ? +1 : +0;
if (flipped == 1 && tsSideFlipped.Ticks == 0)
{
tsSideFlipped = tsLastFrame;
}
ddkfX.KeyTime = KeyTime.FromTimeSpan(tsLastFrame);
//add the DiscreteDoubleKeyFrame to the DoubleAnimationUsingKeyFrames
daX.KeyFrames.Add(ddkfX);
flipRotation %= 360;
frames++;
}
Storyboard.SetTarget(daX, scale);
Storyboard.SetTargetProperty(daX, new PropertyPath(”(ScaleX)”));
sb.Children.Add(daX);
VisualizeSide(sb, tsSideFlipped, 0, TimeSpan.FromMilliseconds((tsSideFlipped.Milliseconds + 100)), back.Opacity, back);
VisualizeSide(sb, TimeSpan.FromMilliseconds((tsSideFlipped.Milliseconds – 100)), front.Opacity, tsSideFlipped, 0, front);
back.Opacity = 0;
}
private static void VisualizeSide(Storyboard sb, TimeSpan tsStart, double opacityStart, TimeSpan tsEnd, double opacityEnd, UIElement side)
{
DoubleAnimationUsingKeyFrames daOpacity = new DoubleAnimationUsingKeyFrames();
SplineDoubleKeyFrame sdkfStart = new SplineDoubleKeyFrame();
sdkfStart.Value = opacityStart;
sdkfStart.KeyTime = tsStart;
sdkfStart.KeySpline = DefineKeySpline(0, 0, 1, 1);
daOpacity.KeyFrames.Add(sdkfStart);
SplineDoubleKeyFrame sdkfEnd = new SplineDoubleKeyFrame();
sdkfEnd.Value = opacityEnd;
sdkfEnd.KeyTime = tsEnd;
sdkfEnd.KeySpline = DefineKeySpline(0, 0, 1, 1);
daOpacity.KeyFrames.Add(sdkfEnd);
Storyboard.SetTarget(daOpacity, side);
Storyboard.SetTargetProperty(daOpacity, new PropertyPath(”(UIElement.Opacity)”));
sb.Children.Add(daOpacity);
}
private static KeySpline DefineKeySpline(double cp1X, double cp1Y, double cp2X, double cp2Y)
{
KeySpline ksStart = new KeySpline();
ksStart.ControlPoint1 = new Point(cp1X, cp1Y);
ksStart.ControlPoint2 = new Point(cp2X, cp2Y);
return ksStart;
}
}
}
March 11th, 2009 at 3:48 pm
I’ve seen a lot of these flip effects, but they are limited to just two images and just flipping vertically. How can you modify to use not just images, but a datagrid or flip multiple controls? and flip it horizontally?
March 11th, 2009 at 4:23 pm
What I demo is not images, but actual controls.
March 24th, 2009 at 9:24 am
Did you try building this with the Silverlight 3 3D animations yet?
March 24th, 2009 at 12:05 pm
I did in my presentation for Mix09. If you skip to the end you will see a Web Slice I did for HatClub that uses projection to flip from one side of a view to another. Here is a link to the example http://thetophat.staging.terralever.com/
June 1st, 2009 at 8:51 am
great example…
thank you
June 24th, 2009 at 1:47 am
Excellent work.
I faced one problem when I tried to replace the controls with textboxes, bottons etc, but I cannot focus onto the textbox and unable to click on the button.
Is there any work around for that.
Thank You.