Now that you have the basic building blocks
of designing the look of an application, let’s talk about creating the
“feel” of an application. The feel of an application is the way it
interacts with the user. The level of interaction depends on the nature
of the application, but many applications should feel alive to the user.
Often this is accomplished with subtle feedback to the user, including
changing the look of the UI in reaction to the user’s actions or using
techniques such as haptic (e.g., vibration) feedback. This feedback is
important to help the user know he is doing something. A common example
of this is the venerable button object. In a typical desktop operating
system, when you move your mouse over a button it changes its look to
indicate you’re over the button. When you click on it, it changes its
look to give you the impression that it is actually pressed (like a
real-world button). This feedback ensures that you can feel confident
that pressing the button is doing what you expect. Some websites lack
this feedback, which simply confuses users (often they don’t know what
is missing). This is where transformations and animations can help you
polish your user interface design.
Transformations
Let’s start with transformations. The idea of a transformation is to
simply change the way an element is drawn on the screen. Let’s take a
simple rectangle:
<Grid>
<Rectangle Width="100"
Height="100"
Fill="Red" />
</Grid>
As you would expect, this rectangle will be drawn as a simple square.
Let’s see what happens when we add a transform (by assigning it to the Rectangle
’s RenderTransform
property):
<Grid>
<Rectangle Width="100"
Height="100"
Fill="Red">
<Rectangle.RenderTransform>
<RotateTransform Angle="30" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
By using a RotateTransform
, you ensure that the object can remain a Rectangle
, but when drawn, the transformation is applied (as seen in Figure 1).
Figure 1. Transformations in action
Using a transformation on a single element rarely is the right thing
to do; usually a transformation is applied to an entire container to
change the look of the container:
<Canvas>
<Canvas.RenderTransform>
<RotateTransform Angle="30"
CenterX="150"
CenterY="150" />
</Canvas.RenderTransform>
<Ellipse Width="300"
Height="300"
Stroke="Black"
Fill="Yellow"
StrokeThickness="2" />
<Ellipse Fill="Black"
Width="50"
Height="50"
Canvas.Left="50"
Canvas.Top="75" />
<Ellipse Fill="Black"
Width="50"
Height="50"
Canvas.Left="200"
Canvas.Top="75" />
<Path Stroke="Black"
StrokeThickness="5"
Data="M 50,200 S 150,275 250,200" />
</Canvas>
In this case the entire smiley face design is rotated (as seen in Figure 2).
Figure 2. Entire container transformed
Table 1 describes and provides examples of the different types of transformations.
Table 1. Transformation Types
You can use the four basic types of transforms singularly or, if you
need to mix transforms (e.g., scale and rotate), you can use CompositeTransform
to combine multiple transforms.
Animations
Although the idea of animations in applications may make you think of
creating the next blockbuster animated feature, that’s not what
animations are for at all. Animations are simply a way to change
properties of XAML elements over time. For example, a simple animation
to change the width of a rectangle would look like this:
<DoubleAnimation Storyboard.TargetName="theRectangle"
Storyboard.TargetProperty="Width"
From="50"
To="250"
Duration="00:00:05" />
Animation elements tell a specific property how to change over time.
This example shows how to change the width of an element named theRectangle
from 50 to 250 over five seconds. The attached properties (Storyboard.TargetName
and Storyboard.TargetProperty
) hint at the fact that animations are not executed on their own but are housed in a container called a Storyboard
. For example:
<Grid.Resources>
<Storyboard x:Name="theStory">
<DoubleAnimation Storyboard.TargetName="theRectangle"
Storyboard.TargetProperty="Width"
From="50"
To="250"
Duration="00:00:05" />
</Storyboard>
</Grid.Resources>
The Storyboard
is embedded in a Resources
section (usually at the main container or UserControl
level) and named so that it can be executed and controlled via code. The unit of work for animations is the Storyboard
. Storyboard
s
can contain one or more animations, but all animations are executed
concurrently (not consecutively). Therefore, if we expand this Storyboard
to include two animations:
<Grid.Resources>
<Storyboard x:Name="theStory">
<DoubleAnimation Storyboard.TargetName="theRectangle"
Storyboard.TargetProperty="Width"
From="50"
To="250"
Duration="00:00:05" />
<DoubleAnimation Storyboard.TargetName="theEllipse"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="00:00:03" />
</Storyboard>
</Grid.Resources>
when this storyboard is executed both animations will execute at the
same time (again concurrently), even though the animations themselves
are against entirely different properties on different objects.
The animations you’ve seen so far have been of the type DoubleAnimation
.
These animations are used because the animation is changing a number (a
double value). There are also animations to change colors (ColorAnimation
) and vectors (PointAnimation
). All three of these animation types change values over a consistent time frame (and are called timeline animations). There are also animations called keyframe animations.
These animations also change properties over time, but the calculation
is based on a value at a specific time in the animation. For example:
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="theRectangle"
Storyboard.TargetProperty="Height">
<LinearDoubleKeyFrame KeyTime="00:00:00" Value="50" />
<LinearDoubleKeyFrame KeyTime="00:00:01" Value="150" />
<LinearDoubleKeyFrame KeyTime="00:00:03" Value="200" />
</DoubleAnimationUsingKeyFrames>
There are keyframe animations for each timeline animation (e.g., double, point, and color) but they are named with the UsingKeyFrames
postfix, as shown above. The Storyboard
attached properties are still used to signify the target of the animation, but instead of a simple To
and From
to specify the values of the animation, one or more keyframes are used. For example, the LinearDoubleKeyFrame
element specifies at what time the value should be a specific numeric property.
In this case, the height should start at 50 at the start of the
animation; move quickly over the first second to 150; and finally slow
down and move to 200 over the last two seconds. The interpolation of the
values between the keyframes depends on the type of keyframe. In this
example the interpolation is linear. You can also use spline and
discrete to achieve curved interpolation and stepped interpolation,
respectively.
With these tools in hand, you should be able
to create the subtle interactive effects that give the user the
impression that he is interacting with real-world objects.