Adventures in Windows 8: Working around the navigation animation issues in LayoutAwarePage

Posted by Laurent Bugnion on Geeks with Blogs See other posts from Geeks with Blogs or by Laurent Bugnion
Published on Tue, 25 Sep 2012 19:41:20 GMT Indexed on 2012/09/26 21:38 UTC
Read the original article Hit count: 232

Filed under:

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.

LayoutAwarePage with background and transformed TextBlock

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

 

© Geeks with Blogs or respective owner