A customer of mine asked me about how to create a "parallactic scrolling" for the background of a GridView. For people that do not know what it is, parallactic scrolling is when you have a background image scrolling slower than the foreground content. This tecnique is mostly used in games to give the impression of depth of field with the overlapping of a number of elements that moves slower when they apper to be far from the observer.
To have a good example of this beautiful effect you can try the music hub of your Windows Phone. The Panorama based scrolling, when coupled with a background image, automatically apply a parallactic effect when you move from a panel to the following.
Coming to Windows 8, there are some application installed by default that shows a similar effect. Weather and Finacial apps shows a partial parallactic effect when transitionig between the start screen and the right content. GridView, ScrollViewer and other controls does not automatically apply this effect (almost not in windows 8 CP), but a simple trick let you easily show the effect in your apps.
First of all you have to produce an element, that is greater than the viewport in the direction you desire your scrolling to work. In the application of my user group it is an image made of people an the total size is almost double of the medium size of a screen device. This image is aligned to left and goes out of the screen on the right. Here is the code:
1: <Grid>
2: <Image x:Name="backImage" Margin="0,0,0,30"
3: HorizontalAlignment="Left" VerticalAlignment="Bottom"
4: Source="/Assets/parallax_people.png" Width="2250" Height="200" Opacity="0.5" />
5:
6: <ScrollViewer x:Name="hScroll"
7: Style="{StaticResource HorizontalScrollViewerStyle}" Margin="0">
8: <!-- insert your content here -->
9: </ScrollViewer>
10: </Grid>
The trick I'm showing works only with ScrollViewer because it requires to handle the ViewChanged event, but you can for sure include a GridView into a ScrollViewer and have the effect enabled for the control. And obviously this also apply to ListView as well.
Now, going to codebehind is is required to subscribe the ViewChanged event. This event is raised every time the user scrolls the content. So I have to recalculate the offset of the background using the HorizontalOffset property and to map the value to the total width of the image. Here is the code:
1: private void hScroll_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
2: {
3: var delta = (this.hScroll.HorizontalOffset / this.hScroll.ScrollableWidth) * (backImage.ActualWidth - this.hScroll.ViewportWidth);
4: this.backImage.Margin = new Thickness(-delta, 0, 0, 30);
5: }
Once you have connected the method to the View the trick is done. In this code I use the Margin property to move the image. At the first sight you would have used a TranslationTranform. Unfortunately the Render tranforms clips the image so I finally adopted the Margin property with a negative value.
In my example you can tune the speed of the content varying the width of the background image, but nothing else is required.