This blog post presents an attached behaviour that gracefully slides the contents of a list into view when used in conjunction with a Pivot control, emulating the Windows Phone 7 email application.
The Windows Phone 7 user interface is based on the Metro Design Language, which favours clear typography, content over chrome and simplicity. If you want to see practical applications of the Metro approach to design, I would highly recommend visiting Scott Barnes’ blog over at riagenic.

Silverlight for Windows Phone 7 provides a basic Metro styling for elements such as Buttons and Checkboxes, it also has a few phone specific controls such as Pivot and Panorama. These controls make it easy to create a basic Metro interface, although again, I refer you to Scott Barnes’ blog, Metro is not all about black and white! However, when using a WP7 phone you will probably notice that the native applications, email, maps and settings, have a bit more ‘flair’, lists gracefully slide into view, or ‘peel’ off the screen when an item is selected. Metro is not just about static style, it is “alive in motion”.
The code in this blog post replicates the graceful slide effect seen in WP7 native applications when a moves from one list to another within a pivot as seen below. The code has been tested on real phone hardware to ensure that it performs well.
To use this code set the attached property ListAnimation.IsPivotAnimated to true for the ListBox (or ItemsControl) contained within a PivotItem. Then apply the ListAnimation.AnimationLevel to any element which you wish to animate as the list slides into view. The animation level describes the delay before each element is animated, for example, the markup below causes the summary to slide in just after the title, with the date following behind.
<controls:PivotItem Header="BBC News"> <!-- animating an ListBox --> <ListBox x:Name="bbcNews" local:ListAnimation.IsPivotAnimated="True"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextLargeStyle}"/> <TextBlock Text="{Binding Summary}" Style="{StaticResource PhoneTextSmallStyle}" local:ListAnimation.AnimationLevel="1"/> <TextBlock Text="{Binding Date}" Style="{StaticResource PhoneTextSmallStyle}" local:ListAnimation.AnimationLevel="2"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </controls:PivotItem> |
The code that achieves this effect is relatively straightforward, so I am going to present it all in one go (omitting all the usual attached property boiler-plate code):
// handles changes in the IsPivotAnimated attached property private static void OnIsPivotAnimatedChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { ItemsControl list = d as ItemsControl; list.Loaded += (s2, e2) => { // locate the pivot control that this list is within Pivot pivot = list.Ancestors<Pivot>().Single() as Pivot; // and its index within the pivot int pivotIndex = pivot.Items.IndexOf(list.Ancestors<PivotItem>().Single()); bool selectionChanged = false; pivot.SelectionChanged += (s3, e3) => { selectionChanged = true; }; // handle manipulation events which occur when the user // moves between pivot items pivot.ManipulationCompleted += (s, e) => { if (!selectionChanged) return; selectionChanged = false; if (pivotIndex != pivot.SelectedIndex) return; // determine which direction this tab will be scrolling in from bool fromRight = e.TotalManipulation.Translation.X <= 0; // locate the stack panel that hosts the items VirtualizingStackPanel vsp = list.Descendants<VirtualizingStackPanel>().First() as VirtualizingStackPanel; // iterate over each of the items in view int firstVisibleItem = (int)vsp.VerticalOffset; int visibleItemCount = (int)vsp.ViewportHeight; for (int index = firstVisibleItem; index <= firstVisibleItem + visibleItemCount; index++) { // find all the item that have the AnimationLevel attached property set var lbi = list.ItemContainerGenerator.ContainerFromIndex(index); if (lbi == null) continue; vsp.Dispatcher.BeginInvoke(() => { var animationTargets = lbi.Descendants() .Where(p => ListAnimation.GetAnimationLevel(p) > -1); foreach (FrameworkElement target in animationTargets) { // trigger the required animation GetAnimation(target, fromRight).Begin(); } }); }; }; }; } |
When the IsPivotAnimated property is first attached, Linq-to-VisualTree is used to locate the parent PivotControl in order to handle SelectionChanged events. However, this is where things get tricky! If a Pivot control contains just two PivotItems, a change in selection is not enough to determine whether the pivot is scrolling to the left or the right! Therefore, we need to handle the ManipulationCompleted event that is fired after the SelectionChanged event to determine the direction of movement.
Once this is done, we can iterate over all of the items in the list, this assumes that the items are being hosted within a VirtualizingStackPanel which is true for a ListBox. For each item that is visible, another Linq query is used to find any that have the AnimationLevel attached property set on them. For each element the animation is created an fired.
Dispatcher.BeginInvoke is used to start each group of animations in order to lessen the impact of starting 10-20 animations simultaneously. Without the use of the Dispatcher, when testing on real hardware there was a small, but noticeable, judder in the sideways scrolling of the Pivot control at the point where the animations were fired. The use of Dispatcher.BeginInvoke means that the construction and firing of the animations are now packaged as separate ‘tasks’ for each element in the list. This means that they do not have to be executed as a single unit of work, allowing the phone to fire a few animations, then perform other tasks. The net result is that the Pivot control still scrolls smoothly between the PivotItems.
The code which creates the required animation is given below, it simply adds a TranslateTransform to the element and creates the required animation / storyboard.
/// <summary> /// Creates a TranslateTransform and associates it with the given element, returning /// a Storyboard which will animate the TranslateTransform with a SineEase function /// </summary> private static Storyboard GetAnimation(FrameworkElement element, bool fromRight) { double from = fromRight ? 80 : -80; Storyboard sb; double delay = (ListAnimation.GetAnimationLevel(element)) * 0.1 + 0.1; TranslateTransform trans = new TranslateTransform() { X = from }; element.RenderTransform = trans; sb = new Storyboard(); sb.BeginTime = TimeSpan.FromSeconds(delay); DoubleAnimation db = new DoubleAnimation(); db.To = 0; db.From = from; db.EasingFunction = new SineEase(); sb.Duration = db.Duration = TimeSpan.FromSeconds(0.8); sb.Children.Add(db); Storyboard.SetTarget(db, trans); Storyboard.SetTargetProperty(db, new PropertyPath("X")); return sb; } |
Interestingly I tried using the Artefact Animator, which has a nice concise API for creating animations in code-behind. However, because it animates elements by setting properties directly, it does not perform well on Windows Phone 7, which can execute storyboards on the composition thread in order to improve performance.
You can download the full sourcecode here: ListAnimation.zip
Regards,
Colin E.
Tags: codeproject, metro, Windows Phone 7, WP7


email: ceberhardt@scottlogic.co.uk
on Google+



Great! It works well, thanks
What’s the license on this code? MS-PL, same as WP7Contrib?
Everything on my blog is under the Creative Commons Attribution Licence.
Damian Mehers mantioned his mods for the LongListSelector which are great however the way that he has implemented is no longer possible using the latest build of the LongListSelector. So wondering is there a way to mod metroInMotion to allow for the new way the LongListSelector works using Link/Unlink.
I think this would be very useful, as I have found quite a few posts and blogs mentioning that the new LLS works much faster than the ListBox due to new ways the virtualisations work and recommending switching to the LLS.
Thanks Jason, I have raised a ticket here:
http://wp7contrib.codeplex.com/workitem/9416
And will look into it.
Cheers much appreciated, love to get those lovely fluid animations back into my lists!
nice tutorial, any tips on implementing a similar effect when transitioning between records. for example in the app i am making i have a list box that takes you to a details page about a specific item. on the details page i have specific info on the item selected, name, address etc. and on the appbar buttons to take you to the next/prev record. what i would like to do is have the new items info slide in instead of just appearing on the button press, any ideas?
thanks for the great blog
[...] Fluid List Animation от Колина Эберхардта с небольшими изменениями. [...]
Hi.
Is it possible to apply such animation to a Panorama Item, filled with a Listbox?
Hi Mac, Yes, I don’t see why not, although the effect might look a bit funny on a panorama. Give it a go, change the references from Pivot to Panorama and see what happens!
Hi Colin,
Thanks for this effect. I was looking for an implementation of this effect for quite some time and I appreciate your neat solution. I have it in use and published in my “MVG Fahrinfo” app.
Thanks,
Georg
Hi Georg,
That’s a cool looking application you have there. I have installed it on my phone and had a quick play. Some of the other Metro In Motion effects might also look good in your application. Have you seen the post about Panorama controls?
Regards, Colin E.
Hi Colin, glad you like it. I stumbled across your Panorama effect yesterday. I may use this in the next version of the app. There is always something to improve
Hi,
i have a small Problem. I don’t know why but when i use Fluid List Animation, only the first item of the list gets the animation!
Does anyone know why?
Hi Rolando, can you share your code? What do you have placed within your Pivot? Also, there have been a few minor bugfixes made to this code. You can find the latest here:
http://wp7contrib.codeplex.com/
Also, why I cannot click again the item I previously selected, after I transferred to Details view then press back. Hope you can help. Thanks!
That is because you are using item selection for navigation. With this technique you must clear selection to allow the same item to be selected again. See my post here for a more in-depth discussion:
http://www.scottlogic.co.uk/blog/colin/2011/04/a-fast-loading-windows-phone-7-navigationlist-control/
The ItemFlyInAndOutAnimations has a problem when the orientation has been change to Landscape. The animation of ItemFlyOut is still in Portrait mode while I’m in landscape view.. What should I do about it?
Hey Colin,
Thanks a lot for the code, I really like the effect.
I ran into a problem though : when it tried to retrieve the pivotIndex when setting the IsPivotAnimatedChanged property, it always returned “-1″, so my items never animated. This seems to happen when the pivot.Items elements aren’t of type PivotItem (for example when you bind the ItemsSource of the Pivot control to a custom collection). I fixed that by replacing the line 65 in ListAnimation.cs :
int pivotIndex = pivot.Items.IndexOf(list.Ancestors().Single());
with :
int pivotIndex = pivot.ItemContainerGenerator.IndexFromContainer(list.Ancestors().Single());
Hope that helps if anyone runs into the same problem.
Cheers.
Thanks for the fix Jeremy – appreciate it!
Great post Colin, thanks. Worked great on a Pivot based app, but with error using Panorama. I think changing ListAnimation.cs Pivot related objects might work…
Hello All,
I really like this effect and look forward to using it in an app of mine but what I’m looking for is that effect when you first start up your phone and the tiles comes in and you tap a button and it does a peel effect. Any help would be much appreciated. many thanks
fernando
Hi, you mean like this one: http://www.scottlogic.co.uk/blog/colin/2011/03/metro-in-motion-part-2-peel-animations/
Regards,
Colin E.
[...] Metro In Motion – Fluid List Animation (Colin Eberhardt) [...]
Great stuff Colin – FYI I’ve made a couple of tweaks to make it work with the Toolkit’s LongListSelector: http://damianblog.com/2011/04/04/fluidlonglistselector/
Nice on Damian, will point people to your blog post
(By the way, it’s Eberhardt, not Everhardt
)
Fixed -sorry about that.
Damien
anFixed -sorry about that.
Damian
enExcellent stuff. Worked perfect and looked very nice. Thank you.
Thanks Brian = glad it worked for you
Great story and a way to use.
Really nice. I tried to realized this effect, but it was a bit more sophisticated (complicated) and did not work so well. Thank you so much!
Metro In Motion – Fluid List Animation | Colin Eberhardt’s Adventures in WPF…
Thank you for submitting this cool story – Trackback from DotNetShoutout…