×
Namespaces

Variants
Actions
(Difference between revisions)

How to create a Settings Flyout using Visual States and Blend

From Nokia Developer Wiki
Jump to: navigation, search
leemcpherson (Talk | contribs)
(Leemcpherson - - Summary)
influencer (Talk | contribs)
(Influencer -)
Line 2: Line 2:
 
{{Abstract|This article explains how to create an animated settings flyout using Visual States in Blend that responds to changes in orientation.}}  
 
{{Abstract|This article explains how to create an animated settings flyout using Visual States in Blend that responds to changes in orientation.}}  
  
{{ArticleMetaData v1.0
+
{{ArticleMetaData <!-- [v1.0] -->
 
|sourcecode= [[File:Settings Flyout using Visual States and Blend for Windows Phone.zip]]
 
|sourcecode= [[File:Settings Flyout using Visual States and Blend for Windows Phone.zip]]
 
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.wgt]]) -->
 
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.wgt]]) -->
Line 19: Line 19:
 
|update-timestamp= <!-- After significant update: YYYYMMDD -->
 
|update-timestamp= <!-- After significant update: YYYYMMDD -->
 
|creationdate= 20140303
 
|creationdate= 20140303
|author= leemcpherson
+
|author= [[User:leemcpherson]]
 
}}
 
}}
  

Revision as of 17:52, 13 March 2014

This article explains how to create an animated settings flyout using Visual States in Blend that responds to changes in orientation.

WP Metro Icon UI.png
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0 SDK
Devices(s): Nokia Lumia 920, Emulator
Compatibility
Platform(s):
Windows Phone 8
Dependencies: none
Article
Created: leemcpherson (03 Mar 2014)
Last edited: influencer (13 Mar 2014)

Contents

Introduction

This article will step you through the process to create a simple, animated settings flyout that can host any type of control you would like. In addition, this article will provide a good introduction to using VisualStates in lieu of Storyboards for animations. Finally, many of the steps will be performed in Expression Blend instead of Visual Studio so you can experience how powerful Blend really is.

Create AppBar & Layout for Settings Flyout

Tip.pngTip: If you already know how to create and modify controls with Blend, skip to the end of this section and copy the XAML into your page.

You can start with any C# XAML-based windows phone app you already have created, or just begin by creating a Portrait-based app in Visual Studio. Next, open the solution you created in Expression Blend. If you have never used Blend before, you should see four different windows: a top-left window containing several tabs, a bottom-left window containing the "Objects and Timeline", a center window containing a Design-time rendering of your page, and a right-side window containing a few more tabs (including "properties"). If you have used Blend before, this may be different depending on how you have changed the settings. On the extreme left-side of the screen will be a toolbox strip.

First, we will create an AppBar with one button that will activate our Flyout. To create the AppBar in blend, select the root item in the "Objects and Timeline" window, [PhoneApplicationPage]. In the properties window on the far right, under the Common heading, click the New button next to ApplicationBar. Click the Elipses (...) button next to Buttons (Collection) and use the menu to add a new ApplicationBarIconButton. Select an IconUri and type some text for the button.

Generated XAML:

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar>
<shell:ApplicationBarIconButton IconUri="/Assets/AppBar/questionmark.png" Text="sample" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Next, we will create a Grid to host our flyout. On the Objects & Timeline window, select LayoutRoot, the main grid that hosts all the controls on the page. You can even expand it using the arrow on the left. Once it is selected, go to the Grid icon that shows in the Toolbox strip on the very left side of the screen. (It looks like 9 squares in a grid.) Double-click it to automatically insert another grid as a child of the LayoutRoot grid. You should then double-click the name of the new grid ([Grid]) and rename it to "SettingsGrid".

Under the "Properties" window on the far right, set both VerticalAlignment and HorizontalAlignment under the Layout heading to Stretch. Since the LayoutRoot contains two rows, find RowSpan under the Layout heading and change it from 1 to 2. Finally, we don't want the grid to have a fixed width or height (the default for Blend controls), find the icon that looks like four arrows next to the Width and Height properties and click them to clear the Width and Height values.

Note.pngNote: The grid will not be have a correct layout until we start to set the Visual States.

The XAML for your LayoutRoot should look like this so far (template comments omitted for clarity):

<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
 
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Setting Flyout using" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="visualstates" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
 
<Grid x:Name="ContentPanel" Grid.RowSpan="2" Margin="12,0,12,0">
 
</Grid>
<Grid x:Name="SettingsGrid" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="1" />
 
</Grid>

Next, so we have something to see. Place a few controls into the new grid. These will be what shows up in the settings flyout we are creating. For the purposes of this article, we will add a StackPanel with Horizontal Orientation and a few plain Buttons. The StackPanel in Blend is combined with the Grid button in the toolbox. Press and hold the Grid Toolbox button and then select the StackPanel button that shows. Double-click it to insert it as a child of the SettingsGrid. Change the Orientation property of the StackPanel to Horizontal and clear the Width and Height values using the 4-ended arrow icons again. To mimic the WP8 AppBar, set the HorizontalAlignment and VerticalAlignment properties to Center.

The Button toolbox button is second-to-last. Double click it a few times to add some buttons. Select the newly created button in the "Objects and Timeline" window, then look at the far-right window where the properties are shown. Change Content property to anything you would like.

Your XAML should look something like this:

    <phone:PhoneApplicationPage
x:Class="SecondaryAppBarUsingVisualStates.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
 
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar>
<shell:ApplicationBarIconButton IconUri="/Assets/AppBar/questionmark.png" Text="sample" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
 
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
 
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Settings Flyout using" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="visualstates" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
 
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
 
</Grid>
<Grid x:Name="SettingsGrid" VerticalAlignment="Bottom" Grid.RowSpan="2">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</StackPanel>
</Grid>
 
</Grid>
 
</phone:PhoneApplicationPage>

Transition Previews Enable

Now that the settings flyout layout is created, we need to add some VisualStates that govern what it looks like and how it changes under different states. To make this process much more intuitive in Blend, we are going to turn on Transition Previews so we can see how the controls animate between states. On the top-left window, select the States tab. On the right-side of that window are two buttons. Toggle the right-most button to enable Transition Previews.

Orientation Visual States

Currently, the flyout can only be in a good position for one of the orientations. However, if your app is going to have both Portrait and Landscape modes, and your flyout is set at the bottom of the screen for Portrait, the flyout will still show at the bottom of the screen in Landscape. We want to mimic the AppBar and have it show on the side of the screen in Landscape orientation.

First, we are going to modify the page to have both orientations. Click on the root item in the "Objects and Timeline" window, [PhoneApplicationPage]. Then, change the SupportedOrientations property under the Common header from Portrait to PortraitOrLandscape. For the rest of this article, if you want to see what your page will look like in either orientation, you can now go to the Device tab on the upper-left window and change the Orientation using one of the two buttons. For the moment, leave the Orientation in Portrait then go back to the States tab.

Ensure that the LayoutRoot grid is selected in the "Objects and Timeline" window, then create a VisualStateGroup by clicking the left button of the two buttons at the top of the States window. You can immediately type a new name for the group, so enter the name "OrientationGroup". Within this group, we will create three visual states that will represent what the page looks like in the Portrait, LandscapeLeft, and LandscapeRight orientations respectively. There is a difference between LandscapeLeft and LandscapeRight because we want the flyout to swap sides to follow the AppBar.


On the new OrientationGroup VisualStateGroup item, click the "Add State" button on the right side and name them. Do this three times to create three states: OrientationPortrait, OrientationLandscapeLeft, OrientationLandscapeRight. Anytime you select one of these states, a red dot will show up next to the state. This indicates that Blend is recording any changes you make to the page while this state is active. When you are making general tweaks to your page, make sure this red record light is OFF by clicking on it. For now, we want it to be on, because we will be making changes that only exist when the state is active.

    <Grid x:Name="LayoutRoot" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OrientationGroup">
<VisualState x:Name="OrientationPortrait"/>
<VisualState x:Name="OrientationLandscapeLeft"/>
<VisualState x:Name="OrientationLandscapeRight"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>


For the next step, you can change the visual to Landscape mode by changing orientation under the Device tab for a better understanding of the following property changes.

Warning.pngWarning: If you make this change while the red, record light is ON, you will have unusual side-effects! The change gets recorded into the state as an Orientation change and you do not want this to happen.

Select the OrientationPortrait visual state. Blend is now recording any changes we make for this state. Select the SettingsGrid and change its VerticalAlignment property to Bottom.

Next, select the OrientationLandscapeLeft visual state. During PageOrientation.LandscapeLeft, the AppBar is on the right side of the screen. Therefore, we also want our setting flyout on the right side. Select the SettingsGrid in the "Objects and Timeline" window and change its HorizontalAlignment property to Right and its VerticalAlignment property to Stretch. Next, select the StackPanel and change its Orientation property to Vertical.

If you select the OrientationPortrait visual state, you will see the controls revert back to their previous state. You can flip back and forth to see the change. Finally, we have to make similar changes to the OrientationLandscapeRight visual state, just for the opposite side. Change SettingsGrid's HorizontalAlignment property to Left and its VerticalAlignment property to Stretch. Change the StackPanel's Orientation again to Vertical.

Warning.pngWarning: Turn off state recording by clicking the red circle or by clicking the "Base" item in the States list.

Your XAML now looks like this and should make it abundantly clear why using Expression Blend is very convenient:

    <Grid x:Name="LayoutRoot" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OrientationGroup">
<VisualState x:Name="OrientationPortrait"/>
<VisualState x:Name="OrientationLandscapeLeft">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.HorizontalAlignment)" Storyboard.TargetName="SettingsGrid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<HorizontalAlignment>Right</HorizontalAlignment>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.VerticalAlignment)" Storyboard.TargetName="SettingsGrid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<VerticalAlignment>Stretch</VerticalAlignment>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(StackPanel.Orientation)" Storyboard.TargetName="stackPanel">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Orientation>Vertical</Orientation>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.VerticalAlignment)" Storyboard.TargetName="stackPanel">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<VerticalAlignment>Center</VerticalAlignment>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="OrientationLandscapeRight"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Settings Flyout Visibility Visual States

The next set of VisualStates will concern the visibility of the settings flyout. We want it to appear and disappear based on user interaction, i.e. clicking of an AppBar button. Return to the States tab of the top-left window and create a new VisualStatesGroup and name it SettingsFlyoutVisibilityGroup. We will be enabling something new for this group. We want the appearance and disappearance of the flyout to be animated. Normally, we could manually create transitions similarly to the way a Storyboard can be used to animate objects. However, a much simpler method is to enable a feature called "FluidLayout". The togglebutton for FluidLayout is located next to the button to create visual states within the group. Enable it.

FluidLayout automatically creates transitions between discrete states like Visibility.Visible and Visibility.Collapsed by taking a snapshot of each and interpolating the middle. All that is required is a default transition time and, optionally, an easing function. Right underneath the SettingFlyoutVisibilityGroup, change the "Default transition" from 0 seconds to 0.4 seconds. Next, click on the icon that looks like a line in a box. This lets you define the easing function. Change it to "Back InOut" (top row, 3rd column).

Next, create two visual states under this new group and name them SettingsFlyoutVisible and SettingsFlyoutCollapsed. We want the default state of the settings flyout to be collapsed, so we need to first change the base state to collapsed. Click on "Base" at the top of the States list. Next, select the SettingsGrid control and change its Visibility to Collapsed. Now, go back to the SettingsFlyoutVisible state and change the SettingsGrid's Visibility to Visible.

Try clicking back and forth between the two states and you should see the settings flyout animate in and out automatically!

Here's what Blend added to your XAML:

<VisualStateGroup x:Name="SettingsFlyoutVisibilityGroup" ec:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.4">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseInOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="SettingsFlyoutVisible">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="SettingsGrid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SettingsFlyoutCollapsed"/>
</VisualStateGroup>

Code-behind to trigger Visual State changes

Save everything in Blend and open your solution in Visual Studio. While Blend's C# IDE is getting better with each release, the IDE from Visual Studio is still superior and more comfortable to use.

First, we need to link up the page's orientation changes to the Visual States we just created. Override your page's OnOrientationChanged method and add the following code to it:

protected override void OnOrientationChanged(OrientationChangedEventArgs e)
{
if (e.Orientation == PageOrientation.LandscapeLeft)
VisualStateManager.GoToState(this, "OrientationLandscapeLeft", true);
else if (e.Orientation == PageOrientation.LandscapeRight)
VisualStateManager.GoToState(this, "OrientationLandscapeRight", true);
else
VisualStateManager.GoToState(this, "OrientationPortrait", true);
base.OnOrientationChanged(e);
}

Next, we want the correct state to be set when the page is loaded. OnOrientationChanged is not called when the page loads so we need to call it manually. Override the OnNavigatedTo method and add the following code:

		protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
OnOrientationChanged(new OrientationChangedEventArgs(this.Orientation));
}

Finally, we want the AppBar button we created to trigger the settings flyout. Create a click event for it and then add the following code to the click event handler:

private void OnAppBarButtonClick(object sender, EventArgs e)
{
if (SettingsGrid.Visibility == System.Windows.Visibility.Collapsed)
VisualStateManager.GoToState(this, "SettingsFlyoutVisible", true);
else
VisualStateManager.GoToState(this, "SettingsFlyoutCollapsed", true);
}

Summary

That completes the entire settings flyout. If you run the code and click on the appbar button, you will see the settings flyout pop out with an animation. The flyout will change positions according to the phone's orientation.

You can improve on this flyout by adding further animations using Visual States, such as the rotation of individual buttons when orientation changes similar to the way AppBarIconButtons rotate.

This article was intended as a primer to both understanding how to use Visual States in a windows phone app and how to use Blend to create them. You can download a full source of the exact solution that was to be generated by following this article.

File:Settings Flyout using Visual States and Blend for Windows Phone.zip

Note.pngNote: If your version of the app has layout problems, such as the buttons dropping to the bottom of the screen during landscape mode, you likely changed the device orientation without turning off state recording. Examine your XAML to ensure that the Visual State code only contains references to the SettingsGrid and child StackPanel.

Version Hint

Windows Phone: [[Category:Windows Phone]]
[[Category:Windows Phone 7.5]]
[[Category:Windows Phone 8]]

Nokia Asha: [[Category:Nokia Asha]]
[[Category:Nokia Asha Platform 1.0]]

Series 40: [[Category:Series 40]]
[[Category:Series 40 1st Edition]] [[Category:Series 40 2nd Edition]]
[[Category:Series 40 3rd Edition (initial release)]] [[Category:Series 40 3rd Edition FP1]] [[Category:Series 40 3rd Edition FP2]]
[[Category:Series 40 5th Edition (initial release)]] [[Category:Series 40 5th Edition FP1]]
[[Category:Series 40 6th Edition (initial release)]] [[Category:Series 40 6th Edition FP1]] [[Category:Series 40 Developer Platform 1.0]] [[Category:Series 40 Developer Platform 1.1]] [[Category:Series 40 Developer Platform 2.0]]

Symbian: [[Category:Symbian]]
[[Category:S60 1st Edition]] [[Category:S60 2nd Edition (initial release)]] [[Category:S60 2nd Edition FP1]] [[Category:S60 2nd Edition FP2]] [[Category:S60 2nd Edition FP3]]
[[Category:S60 3rd Edition (initial release)]] [[Category:S60 3rd Edition FP1]] [[Category:S60 3rd Edition FP2]]
[[Category:S60 5th Edition]]
[[Category:Symbian^3]] [[Category:Symbian Anna]] [[Category:Nokia Belle]]

316 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×