[UPDATE August 16, 2010: Please use the updated version of the tilt code at http://blogs.msdn.com/b/ptorr/archive/2010/08/11/updated-tilt-effect.aspx]
One of the effects that can be seen on the Windows Phone 7 Series videos is the “tilt” effect on buttons and other controls. This effect isn’t built-in to the Silverlight controls (after all, maybe you don’t want your buttons to tilt) but it is trivial to add it. As promised, attached is a simple project that contains a helper library and a sample application that shows how to apply the tilt effect to your application. Please note that this effect is not the final “blessed” effect and the actual calculations used to determine how much to depress / tilt the controls may change. This is just a sample to show how it’s done.
A quick explanation: The tilt effect is added to an element using the TiltEffect.IsTiltEnabled attached property. Typically you would just add this to your application’s main frame (as done in the demo) to enable it anywhere in your application, but if you want a more scoped application of tilt you could choose to put it only on specific pages or other containers such as a Grid.
Adding this attached property binds a MouseLeftButtonDown handler to the element (using the handledEventsToo parameter to get all events, not just those that are unhandled), and the mouse down handler does a couple of things:
- It searches the visual tree upwards, looking for a control that is supposed to tilt (right now, that’s just controls that are ButtonBase or ListBoxItem)
- Once it finds a control, it runs a storyboard against that control, using a plane projection and some computed values to make the projection relative to where you touched the control
The calculation of the tilt is pretty basic:
double halfWidth = element.ActualWidth / 2;
double halfHeight = element.ActualHeight / 2;
double xAngle = Math.Asin((point.Y – halfHeight) / halfHeight) * RadiansToDegrees;
double yAngle = Math.Acos((point.X – halfWidth) / halfWidth) * RadiansToDegrees;
This “cheap” tilt is not actually what you would see with a real-world object; it is a combination of an X rotation and a Y rotation that overlap in subtle ways. A real tilt would first rotate the object around the Z axis and then perform a single plane rotation, but that requires more effort (including the injection of a dummy container in order to rotate the control and then counter-rotate it back again) and I doubt anyone can actually tell the difference in normal usage. Astute readers might note that another solution for a “correct” tilt would be to use a MatrixTransform, but (i) I’ve forgotten all my high school math, and (ii) you can’t animate MatrixProjection so it would require manual updating via CompositionTarget.Rendering… ugh.
So in summary there is no real rocket science here; it’s just a couple of standard Silverlight features put to use. This could probably also be exposed as a Blend Behavior, but I didn’t get around to doing that.
The TiltEffect exposes several attached properties:
- IsTiltEnabled: Set to true to enable tilt on all contained controls
- SuppressTilt: Set to true to suppress tilt on an individual control that would otherwise be tilted
- TiltStrength: Set between 0 and 1 to specify the amount of projection; default can be set on the root container, and individual elements can have overridden values
- PressStrength: Set between 0 and 1 to specify the amount of depression; default can be set on the root container, and individual elements can have overridden values
Play around and let me know what you think!