Updated Tilt Effect

Jeff has posted a version of the Windows Phone 7 “tilt” effect that is packaged as a control, built by Luke. It’s only fair that I update my tilt code too – it uses the same attached property implementation as my previous tilt code, but the new updated tilt algorithm (direct from the shell team) that is used in Luke’s control.

This version uses a global camera effect to ensure that each object tilts not only around its own centre, but is also angled towards the middle of the screen. This effect is accomplished by first translating the object to the middle of the screen doing a normal RenderTransform (in 2D space), and then transforming it back where it came from using a Projection (in 3D space):

TranslateTransform transform = new TranslateTransform();
transform.X = centerDelta.X;
transform.Y = centerDelta.Y;
element.RenderTransform = transform;

PlaneProjection projection = new PlaneProjection();
projection.GlobalOffsetX = -1 * centerDelta.X;
projection.GlobalOffsetY = -1 * centerDelta.Y;
element.Projection = projection;

This is a relatively simple trick that is used in several other places in the Windows Phone 7 animations, something I hope to be posting more on later.

Other than the global camera, a switch to using manipulation events, and some general code clean-up, the basic technique has not changed from the previous version:

  1. An attached property, TiltEffect.IsTiltEnabled, can be placed on any element in the tree (typically the root of a page or even the frame)
  2. When this is done, the control starts listening for ManipulationStarted events on that element
  3. If a manipulation is detected, the code checks the object being manipulated to check whether it is a “tiltable” object
  4. If it is, the appropriate RenderTransform and Projection are added to the element, and the ManipulationDelta and ManipulationCompleted events are hooked
  5. Whenever your finger (mouse) moves, the tilt angle is updated
  6. When the manipulation completes (or when you leave the hit-area of the control) an animation is run to “spring” the control back into place after a short delay

This is all done in a pretty efficient way, such that there is only ever one animation in the app and so that the added transforms and projections are removed after use. Attached is a simple example project that uses the updated effect along with some super-ugly demo pages that show the effect in, errr, effect. It also behaves nicely with tombstoning so that it remembers the scroll positions of each page and the settings you have chosen on the first page. Fingers crossed, this will also make it into the official documentation as a sample such that even developers who don’t read my blog will have access to the tilt effect in their apps (although shame on them for not reading! ;-) ).


Comments (11)

  1. Ryan Buckwalter says:

    I absolutely love the fine detail that is taken with WP7, great stuff. :)

  2. For the application that I am working on right now I needed a control that would allow a user to select

  3. Scott says:

    Very cool, thanks!

  4. Mark Pitman says:

    After applying this attached property, my MouseLeftButtonUp eventhandler no longer fires. Any workarounds or equivalent event I could handle instead?

  5. ptorr says:

    Hi Mark, typically if an event doesn't work directly you can get it by using the AddHandler method with the handledEventsToo parameter set to true. That said, you should probably avoid LeftButtonUp and use ManipulationCompleted instead (although the same caveat may still apply).

  6. Dave Hamilton says:

    Hi, I have just implemnted this on our app, and in general, it all works fine.  I have one issue, and it may actually be the same one that Mark (above) is experiencing, but I would just like some clairifcation.

    I have a listbox, that uses a combination of both the selecteditemchanged, and leftmousebuttonup events.  Everything works fine when the listbox is not scrolling, I press an item, the tilteffect happens, and the item shows as being selected.

    However, when the listbox is still scrolling, it shows the tilt effect, and stops the scroll, but no item is selected.  In all honesty, when i don't have the animations, this is still the same (scrolling stops, and no item selected), however, now that the tilteffect is active, it emphasises this fact.  Is it possible to disable while scrolling, or it this the expected behaviour?

  7. Jobi says:

    Just wondering have you had any measures of the cost for the 'TryStartTiltEffect(FrameworkElement source, ManipulationStartedEventArgs e)' function. We have added this to PhoneApplicationFrame at App.xaml.cs ,TiltEffect.SetIsTiltEnabled(RootFrame, true);

    And for every click or manipulation TryStartTitleEffect loop is working. I am wondering if that causes a lot of CPU cycles. Just wanted to get an idea of minimizing that function call unnecessarly because it has VisualTree parsing as well as two foreach loops working for every manipulation and clicks.

  8. Bert Lagaisse says:

    I got one word for this:


    Integrating the effect in my app took 5 minutes and spices it up with a factor 10.

    Thanks again.

  9. ptorr says:

    Hi Jobi, I did a quick test on the Samsung prototype device (using DateTime.Now at the beginning and end of the function, then subtracting the difference). When a tilt was "successful" (found a tiltable item and computed the tilt centre) it was between 3 and 5 ms; when there was no successful tilt it was 0ms. Note the very first time you tap somewhere it takes about 70 – 80ms while the code is JTted etc.

  10. Beave says:

    Great stuff! I'm going to use this a lot.

    The listbox version is not perfect yet though, ie. the mentioned scroll effect above and if I press an unselected item for a few seconds it won't get selected after I release the item. The previously selected item stays selected.

  11. ptorr says:

    Thanks Beave. For the "tilt happens while scrolling" issue, yes that is inconsistent with the 1st-party apps. It should not show the effect if the list is scrolling. I have a few ideas about how to solve that; you could try building something based on the sample at blogs.msdn.com/…/how-to-detect-when-a-list-is-scrolling-or-not.aspx.

    As for the touch-and-hold case not selecting an item, that is by-design (even without tilt). Typically an application would use this to show a context menu without actually selecting the item.