Partilhar via


Skinning and animating a button

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

You are free to skin your app's buttons and animate them too. Here's how.

Defining how your app looks is important, and you’ve probably spent a long time with the iOS UIButton custom variation, using PNG files to create just the right look for your app. From there, you'll have decided what happens when the user taps on the button: does it flash, display a new image, change size, or all three?

Your Windows Store app button controls can also have their appearance altered, and you can apply custom animation effects too. Let's look at how to create these effects in XAML, and trigger them from C# and C++.

Note  For info about animations for Windows Store apps using JavaScript and HTML, see Animating your UI.

 

Skinning a button control

There are several ways you can change the appearance of a button control, and the most common are:

  • Use the preset styles
  • Use XAML drawing tools, or
  • Use Bitmaps

Let’s look a little closer.

  • Use the preset styles

    If you want your app to follow the standard Windows 8 design guidelines, you don’t need to do much. The existing XAML buttons provide the look and feel you would expect, and you can alter the colors, size, and font styles with a few adjustments to the properties, as shown in Quickstart: styling controls (Windows Store apps using C#/VB/C++ and XAML). These buttons are automatically scaled to look good on any display size.

    When using Xcode, you can use the system designs for Done, OK, Cancel, and so on. In Windows 8, the equivalent buttons in Windows Store apps are stored in StandardStyles.xaml. For example, here's the built-in Play button style when applied to the XAML button, ready to be used in an App bar control:

    The only XAML required to create this style was:

     <Button x:Name="myPlayButton"  Style="{StaticResource PlayAppBarButtonStyle}" />
    

    Note  Most of the styles in StaticResource are commented out by default. To use them, open the file StandardStyles.xaml, find the button you want to use, and un-comment it.

     

    In apps written specifically for Windows 8.1, there is no longer a StandardStyles.xaml file, and instead there is a new type of button called AppBarButton. For example, to create a Play button in a Windows 8.1 app, you would use the following XAML:

    <AppBarButton x:Name="myPlayButton" Icon="Play" Label="Play"/>
    
  • Use XAML

    Let’s say you want to create a version of a button that looks something like this for a media playback app:

    This button consists of a graduated dark background, and a foreground image with a symbol representing Play. You might want to change the foreground image when the user taps on it, so keeping the foreground and background images separate seems a sensible approach.

    Now, before you launch your favorite paint program to create some images, consider how you might programmatically achieve the same result. XAML has many drawing options for you, so you could quickly create a graduated texture background, and a foreground triangle shape. Here’s one way of doing it:

     <Button x:Name="myCoolButton" Height="55" Width="104"  BorderThickness="0" >
                <Grid>
                    <Rectangle Width="104" Height="55">
                        <Rectangle.Fill>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                <GradientStop Color="Black" Offset="0.0" />
                                <GradientStop Color="Gray" Offset="0.03" />
                                <GradientStop Color="Black" Offset="0.25" />
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <Polygon  Points="25,3,25,39,55,21">
                        <Polygon.Fill>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                <GradientStop Color="LightGreen" Offset="0.0" />
                                <GradientStop Color="DarkGreen" Offset="1.0" />
                            </LinearGradientBrush>
                        </Polygon.Fill>
                    </Polygon>
                </Grid>
            </Button>
    

    If you don’t want to enter the XAML by hand, you can use Blend to create the same effect in a more visual way:

  • Use Bitmaps

    The XAML button control allows you to override its contents with your own definition of what it might look like – if say, you want it to display multiple images. The Grid element is used to stack our two objects (one background image, one foreground image), like this:

      <Button x:Name="myBitMapButton" Height="55" Width="104" BorderThickness="0" >
                <Grid>
                    <Image Source="graduated-button.png"/>
                    <Image Source="play-green.png"/>
                </Grid>
            </Button>
    

    You can use the StackPanel element to combine even more objects, such as a TextBlock to make a button like this:

    Here is the code that would achieve that:

      <Grid Background="#FF5989A4">
            <Button x:Name="myBitMapButton"   Height="200" Width="104"  BorderThickness="0" Margin="80,34,0,679" >
                <StackPanel Height="86" >
                    <Grid Height="55" VerticalAlignment="Top" >
                        <Image Source="graduated-button.png" Margin="0,16,0,-7"/>
                    <Image Source="play-green.png" Margin="0,16,0,-5"/>
                    <TextBlock Text="Play"  VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="24,0,22,-15"/>
                    </Grid>
                </StackPanel>
            </Button>
    

The advantage of using XAML over bitmaps is that your images are effectively vectors: they will scale nicely no matter the resolution of the screen on which they will be displayed. When buttons are created using both the bitmap and the XAML approaches and placed side by side, you can see this illustrated clearly when the image is magnified. Of course, you could reduce the scaling effect by supplying images in multiple versions (see Supporting multiple resolutions), but it can soon get tiresome to manage all these files.

A nice benefit of XAML is that you can define templates which multiple controls can use. For example, let's say you wanted to create a series of buttons with the same graduated background, like this:

Rather than defining the graduated background every time, you could create a style which each button would use. In this example, the style is placed in the .xaml file for the page displaying the buttons, say MainPage.xaml. The style is then placed inside the <Page.Resources> section, as so:

        <Style x:Name="graduatedButton" TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Rectangle>
                                <Rectangle.Fill >
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Color="Black" Offset="0.0" />
                                        <GradientStop Color="Gray" Offset="0.03" />
                                        <GradientStop Color="Black" Offset="0.25" />
                                    </LinearGradientBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                            <ContentPresenter />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Notice the use of the <ContentPresenter/> tag, which is a placeholder for any extra content (for example, text or another image). Here's the XAML which declares a button using this new style, and then adds an extra triangle:

       <Button x:Name="myPlayButton" Style="{StaticResource graduatedButton}"  Height="44" Width="135"  Click="myPlayButton_Click" >
            <Grid>
                 <Polygon Points="50,3,50,39,86,21">
                    <Polygon.Fill>
                     <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                         <GradientStop Color="Yellow" Offset="0.0" />
                         <GradientStop Color="YellowGreen" Offset="0.5" />
                    </LinearGradientBrush>
                </Polygon.Fill>
              </Polygon>
            </Grid>
        </Button>

Animating a Button

When writing iOS apps, animating a control such as a button is usually a matter of altering some of the control's properties within a [UIView beginAnimations]/[UIView commitAnimations] block. The equivalent process in a Windows Store app involves creating a Storyboard object. The Storyboard object can be considered as a script for the control to follow, describing how its properties change over time. It's ideal for creating animations that occur when you tap on a button, or for sliding in a new panel of information.

Note  Do not confuse the XAML term Storyboard with the iOS term Storyboard!

 

The easiest way to create an animation is to use Blend. Blend provides a graphical approach for creating the XAML that makes up the storyboard, and it also allows you to preview your animation as you work.

First we'll look at adding a single animation to a specific button, and then we'll cover creating an animation that you can apply to multiple buttons by creating a style. This animation will cause a button to tilt as though you have pushed it into the screen.

Define the button in your XAML file, like this:

 <Button x:Name="TiltButton"   BorderThickness="0" Margin="100,0,0,0" >
            <Grid>
                <Rectangle Width="200" Height="100">
                    <Rectangle.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Color="Black" Offset="0.0" />
                            <GradientStop Color="Gray" Offset="0.03" />
                            <GradientStop Color="Black" Offset="0.25" />
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
                <Polygon  Points="75,5,75,95,145,50">
                    <Polygon.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Color="LightGreen" Offset="0.0" />
                            <GradientStop Color="DarkGreen" Offset="1.0" />
                        </LinearGradientBrush>
                    </Polygon.Fill>
                </Polygon>
            </Grid>
        </Button>

This will produce a button which looks like this:

Now open the project in Blend. Select our button control, and click on the + button in the Objects and Timeline window, as shown here:

Select New to create a new storyboard object, and give it a name, like this:

Tap the Record Keyframe button, which is to the left of the timecode display. This will create a keyframe with all the button's properties in their default positions. Drag the yellow play head line to less than about 0.5 seconds. This will be the location of our second (and in this case, last) keyframe.

Now we can tweak the parameters of the button to get a tilt effect. Under Transform in the Properties view on the right, find Projections and change the Y angle to about -30.

Finally, click on the name of the storyboard in the Objects and Timeline window, and then on the right, make sure AutoReverse is checked. This will cause the animation to bounce back to the original state when it's done.

Save the Blend project, and return to Visual Studio. Make sure to click on Yes to all when asked about reloading the solution. Now our animation is part of the project, but it won't be triggered automatically. Instead we have to change the XAML definition of the button to do two things: first, it has to support transformations (actually, the XAML that is required will be added automatically by Blend) and secondly it has to call a function in our C# code behind file (we'll have to add that ourselves). Here's the updated XAML:

<Button x:Name="TiltButton"   BorderThickness="0"  Click="TiltButton_Click" >
            <Grid>
                <Rectangle x:Name="rectangle" Width="200" Height="100">
                    <Rectangle.Projection>
                        <PlaneProjection/>
                    </Rectangle.Projection>
                    <Rectangle.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Color="Black" Offset="0.0" />
                            <GradientStop Color="Gray" Offset="0.03" />
                            <GradientStop Color="Black" Offset="0.25" />
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
                <Polygon  Points="75,5,75,95,145,50">
                    <Polygon.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Color="LightGreen" Offset="0.0" />
                            <GradientStop Color="DarkGreen" Offset="1.0" />
                        </LinearGradientBrush>
                    </Polygon.Fill>
                </Polygon>
            </Grid>
        </Button>

And here is the C# function in the code behind page that will trigger the animation:

private void TiltButton_Click(object sender, RoutedEventArgs e)
        {
            TiltAnimation.Begin();
        }

If you are using C++, you can use similar code:

void MyApp::MainPage::TiltButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    TiltAnimation->Begin();
}

When you run this app, you'll see that when you tap on the button, it will quickly tilt slightly, like this:

In the section above, we looked at how creating a style could speed up the implementation of the user interface. Here's how to add a storyboard to a style, such that any button control created with the style will inherit the animation. The secret is to use the VisualStateManager object, as this lets you define specific storyboards per button event. Here's the XAML that will trigger a brief animation when you tap on the button. As before, this XAML should be placed in the <Page.Resources> section, and the style applied to your button.

 <Style x:Name="graduatedButton" TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
                            <Grid.RenderTransform>
                                <CompositeTransform/>
                            </Grid.RenderTransform>
                            <VisualStateManager.VisualStateGroups>                             
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>                                 
                                        <VisualState x:Name="Pressed">                                    
                                            <Storyboard >
                                            <DoubleAnimation Duration="0" To=" 0.9" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="grid"/>
                                            <DoubleAnimation Duration="0" To=" 0.9" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="grid"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>                              
                            </VisualStateManager.VisualStateGroups>
                            <Rectangle >
                                <Rectangle.Fill >
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Color="Black" Offset="0.0" />
                                        <GradientStop Color="Gray" Offset="0.03" />
                                        <GradientStop Color="Black" Offset="0.25" />
                                    </LinearGradientBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                            <ContentPresenter />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Using VisualStateManager means you don't even need to trigger the storyboard animation with Begin(), as it's triggered automatically once the state is activated.

Topics for iOS devs

Resources for iOS devs

Windows 8 controls for iOS devs

Windows 8 cookbook for iOS devs

Skinning and animation topics

Getting started: Animation

How to: Create User Interfaces Using XAML and Expression Blend

Animating your UI (Windows Store apps using C#/VB/C++ and XAML)

Storyboarded animations (Windows Store apps using C#/VB/C++ and XAML)

Storyboarded animations for visual states