Adventures in Windows 8: Working around the navigation animation issues in LayoutAwarePage
- by Laurent Bugnion
LayoutAwarePage is a pretty cool add-on to Windows 8 apps, which facilitates greatly the implementation of orientation-aware (portrait, landscape) as well as state-aware (snapped, filled, fullscreen) apps. It has however a few issues that are obvious when you use transformed elements on your page. Adding a LayoutAwarePage to your application If you start with a blank app, the MainPage is a vanilla Page, with no such feature. In order to have a LayoutAwarePage into your app, you need to add this class (and a few helpers) with the following operation: Right click on the Solution and select Add, New Item from the context menu. From the dialog, select a Basic Page (not a Blank Page, which is another vanilla page). If you prefer, you can also use Split Page, Items Page, Item Detail Page, Grouped Items Page or Group Detail Page which are all LayoutAwarePages. Personally I like to start with a Basic Page, which gives me more creative freedom. Adding this new page will cause Visual Studio to show a prompt asking you for permission to add additional helper files to the Common folder. One of these helpers in the LayoutAwarePage class, which is where the magic happens. LayoutAwarePage offers some help for the detection of orientation and state (which makes it a pleasure to design for all these scenarios in Blend, by the way) as well as storage for the navigation state (more about that in a future article). Issue with LayoutAwarePage When you use UI elements such as a background picture, a watermark label, logos, etc, it is quite common to do a few things with those: Making them partially transparent (this is especially true for background pictures; for instance I really like a black Page background with a half transparent picture placed on top of it). Transforming them, for instance rotating them a bit, scaling them, etc. Here is an example with a picture of my two beautiful daughters in the Bird Park in Kuala Lumpur, as well as a transformed TextBlock. The image has an opacity of 40% and the TextBlock a simple RotateTransform. If I create an application with a MainPage that navigates to this LayoutAwarePage, however, I will have a very annoying effect: The background picture appears with an Opacity of 100%. The TextBlock is not rotated. This lasts only for less than a second (during the navigation animation) before the elements “snap into place” and get their desired effect. Here is the XAML that cause the annoying effect: <common:LayoutAwarePage x:Name="pageRoot"
x:Class="App13.BasicPage1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:App13.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="Assets/el20120812025.jpg"
Stretch="UniformToFill"
Opacity="0.4"
Grid.RowSpan="2" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="backButton"
Click="GoBack"
IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}"
Style="{StaticResource BackButtonStyle}" />
<TextBlock x:Name="pageTitle"
Grid.Column="1"
Text="Welcome"
Style="{StaticResource PageHeaderTextStyle}" />
</Grid>
<TextBlock HorizontalAlignment="Center"
TextWrapping="Wrap"
Text="Welcome to my Windows 8 Application"
Grid.Row="1"
VerticalAlignment="Bottom"
FontFamily="Segoe UI Light"
FontSize="70"
FontWeight="Light"
TextAlignment="Center"
Foreground="#FFFFA200"
RenderTransformOrigin="0.5,0.5"
UseLayoutRounding="False"
d:LayoutRounding="Auto" Margin="0,0,0,153">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="-6.545" />
</TextBlock.RenderTransform>
</TextBlock>
<VisualStateManager.VisualStateGroups>
[...]
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
Solving the issue
In order to solve this “snapping” issue, the solution is to wrap the elements that are transformed into an empty Grid. Honestly, to me it sounds like a bug in the LayoutAwarePage navigation animation, but thankfully the workaround is not that difficult: Simple change the main Grid as follows:
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.RowSpan="2">
<Image Source="Assets/el20120812025.jpg"
Stretch="UniformToFill"
Opacity="0.4" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="backButton"
Click="GoBack"
IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}"
Style="{StaticResource BackButtonStyle}" />
<TextBlock x:Name="pageTitle"
Grid.Column="1"
Text="Welcome"
Style="{StaticResource PageHeaderTextStyle}" />
</Grid>
<Grid Grid.Row="1">
<TextBlock HorizontalAlignment="Center"
TextWrapping="Wrap"
Text="Welcome to my Windows 8 Application"
VerticalAlignment="Bottom"
FontFamily="Segoe UI Light"
FontSize="70"
FontWeight="Light"
TextAlignment="Center"
Foreground="#FFFFA200"
RenderTransformOrigin="0.5,0.5"
UseLayoutRounding="False"
d:LayoutRounding="Auto"
Margin="0,0,0,153">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="-6.545" />
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
<VisualStateManager.VisualStateGroups>
[...]
</Grid>
Hopefully this will help a few people, I banged my head on the wall for a while before someone at Microsoft pointed me to the solution ;)
Happy coding,
Laurent
Laurent Bugnion (GalaSoft)
Subscribe | Twitter | Facebook | Flickr | LinkedIn