Silverlight 3D flip animation

Date 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

12 Responses to “Silverlight 3D flip animation”

  1. David Roh said:

    Hi Joel,

    Thank you for sharing this – it’s very nice!

    David

  2. » Silverlight Flipping Tiles Animation said:

    [...] 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 [...]

  3. Rick said:

    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?

  4. Richard said:

    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;
    }
    }
    }

  5. Emma said:

    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?

  6. joel said:

    What I demo is not images, but actual controls.

  7. Hari said:

    Did you try building this with the Silverlight 3 3D animations yet?

  8. joel said:

    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/

  9. Tode said:

    great example…

    thank you

  10. Irfan said:

    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.

  11. Jim said:

    Excellent example indeed!!

    However, I do run into the same problem, when replacing the controls with functional ones.

    Any suggestions?

    Regards,
    Jim

  12. Kostkac said:

    Hi, it is possible to create this only with XAML?

    Thanks, K

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">