From time to time, it’s handy to have a popup available in most applications (often a dialog popup, so the underlying controls aren’t accessible anymore), even in Silverlight-apps. But just letting it appear out of nowhere doesn’t look too nice; it’s ok for most apps, but for a Silverlight app (which is, after all, about creating a rich experience, including some nice animations) I’d typically expect something more. A nice animation, for example. So I decided to make one. 🙂
In lack of inspiration for a good name, let’s just call it a "Scale-out-from-Sender"-popup, meaning the popup will start on the center of the button you click and scale out to the destination you want it to appear.
A picture says more than a thousand words, and a running app says more than a description of an app, so you can view this effect in action here.
Now: how do we get this done?
First of all, I wanted to create the animation dynamically, in code, so I could re-use it on any object – a user control in this case, but I could just as easily apply the generated animation to any other control. I wrote an animation class to get this done, containing 2 public methods: CreateTranslateAndScaleIn and CreateTranslateAndScaleOut, both accepting 5 parameters: the object to be animated (in this case, the usercontrol which will "pop up"), and the X & Y-coördinates of origin and destination. Origin would typically be the middle point of the button we clicked to show the popup, while destination would be the lower-left corner of the place where we want the popup to appear.
The storyboard itself consists of a combination of DoubleAnimationUsingKeyFrame-animations: 2 scale-animations (scaleX and scaleY from nothing to 1), 2 translation-animations (to get the control from origin to destination) and an opacity-animation (to make it look nice ;-)). I create these animations in code, add them to a storyboard, set the storyboards’ target and pass the storyboard back to the calling procedure.
CreateTranslateAndScaleIn will create the Storyboard to get the control from the sender location to the destination, CreateTranslateAndScaleout will create one to animate it back from destination to sender.
Once we’ve got this in place, the rest is quite easy. On the Page.XAML, I created 5 buttons on different places on the page to show the effect from different angles. I also created the control I want to "pop up", myPopup.XAML. This is a pretty standard control, its constructor accepts the needed coördinates and in the constructor the storyboard is created and started. As a "background" to the control, I added a stretched rectangle, to achieve a "dialog box" effect – by doing this, the underlying controls aren’t available anymore untill the popup is closed. This also means the Storyboard is created not on the complete control, but on the Border-elements which defines the popup (we off course do not want to animate the "background").
One thing to keep in mind: if you want the animation to look right, put the RenderTransformOrigin of the element you want to pop to 0,0 (left-lower-corner), ’cause that’s what the destination coördinates translate to.
The popup control also contains a "close"-button. When this is clicked, the scale-out Storyboard is created and started, and a handler is added to its Completed-event to remove the control after the Storyboard has been completed.
… and that’s about it! 🙂
I could off course refine this a little more, eg by calculating the destination when I generate the animation instead of in the constructor, by getting the width/height from the control instead of having them hard-coded, etc; but this gives you a general idea of how this kind of effect is achieved.
All in all, not that hard to do, and quite a nice effect to have! Enjoy playing with it, source code can be downloaded here.