This is a beginner's guide on how to build robust, scalable, and easily editable buttons, as well as covering Template Binding to the Style, Layout, Animation, Opacity Masks, Scalability, and Reuse.
Introduction
Do all buttons have to look so traditional? Not in Silverlight!
We can now make them beautiful thanks to the power of Silverlight and Blend, shown wonderfully by Timmy Kokke in his Glass Orb Button article. But we can do more than just colourful, so I'd like to share some ideas for how we can go a bit further. As well as discussing how to build your buttons with consideration to: Layout, Styles, Animation, Scalability, and Reuse.
So if you are a developer looking to improve your artistic skills, a designer who is new to the Expression Blend environment or just struggling with the concepts of Expression Blend, then this may be for you, or for someone on your team!
Background
There are many articles online about making buttons, be it in Photoshop, Illustrator, CorelDraw, etc., and these can be found by simply searching for "glass button" in Google Images. And these can provide inspiration, but most importantly: almost all the principles can be applied to Silverlight using Expression Blend and Expression Design. So rather than focusing on re-creating a specific button parrot fashion, my aim will be trying to help you get the best out of Expression Blend for your own individual creations. Expression Blend and Silverlight are not just a vector artwork package, with bits bolted on. It is so much more, and requires a slightly different way of working. As well as extra considerations when designing artwork for applications. So I will try to guide you in making robust buttons (UserControls
), with principles that can be applied anywhere in the Blend environments, discussing things like "Scalability", will your button look good and function correctly at all resolutions, etc. Some of the techniques and operations you may want to apply will not scale, like Margins and Strokes, as well as Effects like Blur and Drop Shadow. Hopefully, I can steer you on a path to avoid some painful errors, building clean flexible controls that work well and as expected.
Overview
In this tutorial, I will be covering everything to recreate the first button shown in the introduction image above. I will be approaching this tutorial from the perspective of a Designer who understands vector artwork, but with no knowledge of Silverlight or Expression Blend. I will attempt to document every step at the start, hopefully speeding up as we go along to prevent it becoming tedious. Meaning, if you are new to Silverlight and Expression Blend, I would recommend you do not skip sections. This tutorial will also act as a pre-requisite to any further tutorials I do.
I have sub-divided the tutorial into sections for easier reference:
- Basic Button, Layout, and Components
- Modifying the Button
- Scalability Issues
- Cosmetic Surgery
- Interaction and Animation
- Multiple Colours and Final Touches
- Focused, Disabled, and Content
Section 1 - Basic Button, Layout, and Components
Open a new Silverlight project in Expression Blend and call it something like "TestButton
". Select the Button icon in the left hand tool bar.
Now place a button on the screen, by either dragging the desired button size and location on the Artboard (centre layout panel), or by double clicking on the Button icon. Try each method and see the different results. Now let's consider what size the button should be and what is controlling the size of your button. And how this differs from a vector artwork package.
The Artboard provides some manipulation and control over the size of your button and its relationship to its parent. But I would like you to focus on the Layout section of the Properties tab on the right to control your button.
Take a look at the white dots that appear on the right of each setting, this is an indicator that the setting is not "Default". Now these dots are also buttons, so click on each white dot in the Layout section of the Properties tab and select "Reset".
Notice how your button changes to eventually fill the LayoutRoot
. (Its parent object is in the Objects and Timeline tab.) In Blend, it is always desirable to have your Object
s (Control
s) to dynamically resize and stretch to fit its parent Object
.
Rather than defining absolute values, like fixed Width
and Height
, it's better to allow the parent object to control the size of your Object
. Select LayoutRoot
in the Objects and Timeline and change its size in the Layout section of the Properties tab. See how this controls and defines the size of your button.
Set the LayoutRoot
back to its defaults, by using the small white buttons and selecting "Reset". Now we wouldn't want the button to completely fill our screen, and we can control the button's size within the parent object (LayoutRoot
) using Margins. So with the button selected in Objects and Timelines, enter some values for the Margins, or drag the edges of the button in the Artboard.
(Values can be negative, as well as positive.)
I won't discuss Horizontal and Vertical Alignment at present, other than saying they should both be set to Stretch
, which is the default setting, so use the Reset feature. It's important to understand that fixed Width and Height is generally bad, unless it is the "Root Object".
In Objects and Timeline, click on "[UserControl]" and notice it has a fixed size of 640x480 (not auto sized). This is the "Root Object", the parent to all the child elements/objects that make up this Object
(or UserControl
).
Everything (all children) should take instructions on how to layout from the parent, only it should have a fixed size.
So to summarise, I hope you understand that there are two basic ways we control the size of an object:
- Fixed Width and Height: Button will not scale when the parent object resizes.
- Auto sized Width and Height with Margins set: Button will scale with parent object.
There are more, which we will introduce later...
Now select your button in Objects and Timeline, and Reset all the Layout properties of your button back to their defaults. Set the Width and Height to 100x100 pixels (fixed size). I know I said it is bad to use fixed Width and Height, but for our purposes here, the button will be our "Root Object". (It will control the size of all the child items we are going to play with.)
Now right click on your button and choose Edit Template > Edit a Copy. You should be presented with a window named "Create Style Resource". Give this Style Resource (a button Style
) a name like "ButtonRound1
" and select OK.
(Don't worry about what you call it, as it can be changed in the Resources tab later, and all the references to it will automatically be updated.)
Hopefully, you will have spotted that in getting in to the button Template
, we had to create a button Style
. So what is the difference? Basically, a Style
should hold the general properties of the UserControl
(button), things like Colour
and Text
should be controlled in the Style
. The Template
is the bits and pieces that make up the control (Button
), and inherits properties like Colour
and Text
from the Style
using Template Binding.
It would not be desirable to have to change the colour of all the Template
components, which could be numerous, when it can be done in a single click in the Style
!
Style
s can be compiled in to Resource Dictionaries, which your developer may request, and this can be done at anytime, using drag and drop in the Resources tab.
But let us move on with our button and have a look at exactly what is the "Button Template". In the Objects and Timeline tab, we can see a breakdown of all the components/bits that make up a button.
I've expanded that grid to expose the child objects, and for clarity, I will refer to the parts that make up the template as elements. Before we delete most parts/elements of the template, let's have a quick look at what we have and how it works. It is composed mostly of Grid
s and Rectangle
s which have Colour
properties applied to them. As well as a Content Presenter, which is a place holder to display Content
specified in the root of the object, or defined at runtime by the developer.
There are also two Border
item/elements which have similar properties to a Rectangle
, but basically has more control over its edge and corner properties. In the Template
, select the Grid
directly above the BackgroundAnimation
element. Now look at the Properties tab on the right hand side and you will see that the background colour has a small orange dot next to it on the right side.
There is also an orange rectangle around the colour picker. These indicators signify that the background colour is Template Bound to the Style
and should not be changed here. Instead, we should edit the Style
if we want to change this colour.
To edit the Style
, click on the Style icon (looks like a pie chart, cheese, or Packman) in the top left corner of the Artboard.
All the components/elements in the Objects and Timeline tab will disappear, and will be replaced with "<>Style" to signify that we are in the Style
.
Now in the Style
, go to the Properties tab and change the background colour to bright red. Go back into the Button Template, by clicking on the Grid node to the right of the Style icon.
Now the element named Grid
in the Objects and Timeline tab should be automatically selected.
Look again at the Background colour in the Properties tab to see if it has changed. (Hopefully, it will be bright red.) If you hunt about, you will see that the BorderBrush
of the Style
, is Template Bound to the BorderBrush
of the element named Background
. As is the BorderThickness
, allowing us even more manipulation of how the UserControl
(Button
) will look, just by modifying the Style.
But we cannot control everything from the Style
and to pull out every Resource would be excessive and unwieldy. For example, we cannot easily control or reference the MouseOver
colour States in the Style
and I will explain why later.
Select the BackgroundGradient
element in Objects and Timeline and have a look at the Background Fill colour.
Note that it is a white gradient, with changes in its Alpha
(opacity/transparency) at four Gradient Stops along the Ribbon
.
This allows the solid block colour of the element underneath it BackgroundAnimation
to show through in the form of a coloured gradient. And the principle of applying overlays to a solid block colour can be very powerful, as well as easy to edit or reference by the Style
or a Colour Resource.
Now let's look at how the button changes its appearance for different States, like RollOver
, Pressed
, and Disabled
. Ensure you are on the States tab (top left corner) and select the MouseOver
state. Now expand all the elements in the Objects and Timelines tab. Click the "Show Timeline" icon to the right of "MouseOver" in the Objects and Timeline tab.
Note that there is now a red border around the Artboard and that some blue Keyframes have become visible in the Objects and Timelines tab. (Keyframes are points that define a change or a fixed value at a certain point in time. By default, these will occur instantly at time zero.) Select the BackgroundAnimation
element and look at the Opacity
value in the Property tab, see that it is set to 100%. Now change the States Manager back to "Base" and see that the Opacity
is now set to 0%.
The BackgroundGradient
element also changes, as the Alpha
(Opacity
) of three of the four Gradient Stops is reduced. This allows the background colour to show through more in the lower half, but not in the top half. Investigate and play with the different states, but remember to use the Base
state to create and modify your elements, as this defines the default properties or starting point for all other States before you modify them. (You can work in the "Base" state and simulate another by clicking on the eye icon to the left of that state.)
Hopefully, you have realised that DisabledVisualElement
and FocusVisualElement
are just overlays and borders (Stroke
), respectively.
One last thing before we start modifying our default button. Earlier when I spoke about what defines the size of a button, I ignored, for simplicity, something else that can define the size of a button. What would happen if I told the button to only be as large as it needs to be? To do this, you will firstly need to come out of the Button Template. Either by clicking the "(Button)" node in the top of the Artboard:
Or the "Return Scope" icon in Objects and Timeline.
Now change the Layout properties in the Properties tab as shown:
Ensuring all properties are Reset, except for the Horizontal and Vertical Alignment, which are both set to Centre
. The button will shrink to a size, just large enough to accommodate the contents (plus a little bit, which is called Padding). Increase the Font Size to say 48pt, and see how this affects your button. Go into the Style
for the button, and in the extended attributes of Layout in the Properties tab, you will find an option for Padding.
Alternatively, just type "padding" into the search at the top of the Properties tab.
Now change the values to 40
and see how this affects the size of the button.
If you want to see how the Padding is set, look in the Properties tab of the ContentPresenter
inside the Button Template. (Remember to clear the search to unhide the properties that do not fit the search in the Properties tab.)
The Margin
property is Template Bound to the Padding
property of the Style
.
So when I define a Padding
change in the Style
or outside of the Button Template, it is actually the Margin
of the ContentPresenter
inside the Button Template that we are controlling. At the risk of labouring the point, I'm trying to show the function of Styles. As well as hopefully demonstrating that the initial designer may not have final control over the size of the button. It can depend on the Size
and Layout
of your page, as well as the Content
defined within it.
So I recommend you consider ensuring your work functions correctly at all sizes!
Section 2 - Modifying the Button
So we have looked at the different elements that make up a default button, and we could manipulate the elements we have. Instead, let us Delete everything else, except the ContentPresenter
. Don't worry about the warning message that the animations will be lost.
(This is because we are removing elements that have animations applied to them.)
We are now left with the basic shell of a button, with a Template
consisting of an element of type Grid
and a child element of type ContentPresenter
. Why do we have a Grid
as the Root element? Because Grid
it is the best Layout Container for formatting (controlling) the layout of child elements. Not only can Grid
contain multiple children, it can be subdivided to constrain the proportions and layout of the child elements. We will be using Grid
to group elements that apply to a specific part of a button, like "Rim
", or "Face
" for example.
So let's get started and create a round button with a Rim
. Select Grid
in the Objects and Timelines tab. Then click and hold the Rectangle tool in the toolbar on the left to reveal the Ellipse tool.
With the Ellipse icon on the toolbar, double click it, and an Ellipse
will appear as a child element of the Grid
element.
If you have been following from the beginning, your Artboard should look like this. The Ellipse
does not fill the whole area of the button, instead it is inserted at a size of 100x100 pixels in the top left corner. This is because, even though the button would like to be 100x100 pixels, the ContentPresenter
is controlling the size of the button due to the Layout, Font Size, and Padding changes we previously set for the button. Come out of the Button Template by using the Up Scope icon in Objects and Timelines, and Reset the Font Size from 48 to 8.25. Notice how the button shrinks, and what was a circle is now a squashed ellipse.
Next give the button a fixed Width and Height of 100x100 pixels.
The text now does not display properly, due to the excessive Padding
we set in the Style
. But the ellipse now spans the width of our button, which is what we want. So go to the Style
, using the Style icon.
Now in the extended properties of the Layout section, Reset the Padding back to the Default value of 3. Now the text displays properly, but the ellipse is still not a circle. So select the Ellipse using the icon to the right of the Style icon, to enter the Button Template.
(It may say "ContentPresenter", and will depend on what was the last selected element in Objects and Timeline of the Button Template.)
Ensuring you have the Ellipse selected, look at the Layout properties in the Properties tab for the Ellipse. Notice that we have settings applied that we did not set.
This was Expression Blend trying to insert an Ellipse to fill the Button Template, which it thought was 100x100 pixels. But the ContentPresenter
was controlling the size of the Button Template, making it larger, so the Layout just did the best it could.
That may be a little confusing, but when working at design time, set a Fixed Size for the parent object (button) and set the children to automatically fill it. Reset all the defaults of the Ellipse in the Layout section of the Properties tab. (Or delete the Ellipse and double click the Ellipse icon on the left tool bar to insert a fresh Ellipse.)
Hopefully, you have an Ellipse
element and a ContentPresenter
element.
In the Artboard, the button text is no longer visible as it is obscured and behind the Ellipse. Click on the "Eye" icon next to each element to show or hide what is behind it. (In Photoshop, layers build from the bottom up; in Expression Blend, they build from the top down.)
So select the ContentPresenter
element and drag it below the Ellipse
and therefore in front of the Ellipse
, as we are always going to want the ContentPresenter
in the front. But every time we add a new element, it is positioned at the bottom of the list and therefore in front of the ContentPresenter
. To avoid this annoyance, we will build the framework of our button in its own dedicated Grid
.
Right click on the Ellipse and select Group Into > Grid.
Now rename the newly created Grid
and call it "Rim
".
Now select the Ellipse and duplicate the Ellipse by using the keys "Ctrl +C", "Ctrl +V" (Copy and Paste). You should now have two Ellipse
s within the Grid
called Rim
and no problem with the ContentPresenter
being covered.
Now is a good a time as any to start naming our components/elements.
So select the top Ellipse
in the list and call it BGround
, then select the bottom Ellipse
in the list and call it RadialGradient
.
With the Ellipse
element named BGround
selected, and using the Advanced Properties button, change the Fill
property to Template Binding > Background.
This will set the Fill
of our Ellipse
and therefore the overall colour of our UserControl
editable from the Style
of our UserControl
. (We can't see any results or colour change yet, because we have another Ellipse
named RadialGradient
on top).
Click on the "Eye" icon of the RadialGradient
element to show the Fill
(Background
) colour of the Style
.
If you have not changed the Background
colour of the Style
, your button should look like this:
Very boring, so let us set the RadialGradient
element as an overlay, to control the Opacity
and Tone
of the Background
colour below.
Select the RadialGradient
element and in the Properties tab, change its Fill
to "Gradient Brush".
Next, change the gradient from Linear
to Radial
.
Now set both Gradient Stops on the Ribbon
to White, and position like mine at locations: 85, 90, 95, and 100 on the Ribbon
.
(Click anywhere in the Ribbon
to add another Gradient Stop and drag off the Ribbon
to remove to a minimum of 2).
Next, set the Gradient Stop at Ribbon
location 85 to have an Alpha
(Transparency
) of 0%. Repeat the above step for the Gradient Stop located at 100 on the Ribbon
. This should give you a button looking like this:
Not very pretty yet, but you can see the Rim forming. Zoom in on your button and see that we have an annoying black line on the outside edge. This is getting in the way of our gradient, which is the "Stroke
" of both Ellipses. So let's get rid of it. Select Stroke
for each Ellipse
and set to "No Brush
".
The Rim is starting to look better, but the contrast is rather strong. We can adjust this by either adjusting the Alpha
of the Gradient Stops at 90 and 95 on the Ribbon
to say 60%:
Or by adjusting the Opacity
of the whole element.
My preference at the moment is to make the adjustment in the Gradient Stops, as it allows simpler control for adjusting the whole element between 0% and 100%. (Or does it? We will discuss that later...)
Moving on, we want our Rim
to sit around the outside of our button Face
. I want the page colour to show through on the inside edge of the Rim
. So I will change my page colour to a horrid red for demonstration purposes. Use the Return Scope icon to come out of the Button Template. And change the Fill
colour of the LayoutRoot
element to Red.
Now to make the centre of the Rim
transparent, we can use an Opacity Mask. And we could set an Opacity Mask on both Ellipse
s. (But I'd like to save them for some further effects I might wish to apply).
Instead, I'm going to apply it to the parent object of the Ellipse
s: the Grid
element named Rim
, as it also supports an Opacity Mask. So select the button in Objects and Timeline and go back in the Button Template. Select the Grid
element named Rim
; in the Properties tab, select Opacity Mask. Give it a Radial Gradient, with Gradient Stops at 0, 84, and 85 on the Ribbon
.
Set the Alpha
to 0% for the 0 and 84 Gradient Stops, and 100% for the 85 Gradient Stop. (The Gradient Stop at 0 is not actually needed, but left in for clarity.) The inner 85% of all the elements that make up your button Rim
are now invisible.
Test it by changing the Fill
colour of the "LayoutRoot
" Grid
. (Remember that you are in the Button Template and need to press Return Scope to manipulate the "LayoutRoot
" Grid
colour).
Now back in the Button Template, we will start creating our button Face
to sit inside the Rim
. Ensure you have the Grid
element named Rim
selected. Double click on the Ellipse icon in the left tool bar, which inserts a new Ellipse
inside of the Grid
named Rim
. This is not going to work for us, as the inner 85% of the Ellipse
is missing. This is because, it is being controlled by the parent object, the Grid
element named Rim
, which has an Opacity Mask applied to it, and as such affects all of its child elements. So we need to move it out of the parental control of the Grid
element named Rim
.
Select the Ellipse in Objects and Timeline and drag it on to the element named "[Grid]
". (Notice how the Ellipse
now sits in front of the ContentPresenter
).
Select the ContentPresenter
and drag it to the bottom of the list.
Now select the Ellipse, right click and choose Group Into > Grid. Rename the newly created Grid
and call it Face
. Select the child Ellipse
element and rename it "BGround1
".
(Notice that two elements/components cannot share the same "X" name!).
Now to make the Face
the same colour as Rim
: Template Bind the Fill
colour of the BGround1
element to the Background
colour of the Style
.
We cannot see the Rim
in the Artboard, because it is obscured by the newly created Face
.
We need to reveal the Rim
area as well as a clearance gap between the Rim
and the Face
. From what I have shown you so far, we could apply an Opacity Mask to the Face
. That is inverse/opposite of the Opacity Mask on the Rim
. But this would mean is only the central 85% of the child elements of the Face
would be visible. (Awkward, and no good if we ever want to use the Stroke
of a child element).
Margin
could be another method of controlling the size of the Face
. Select the Grid
element named Face
, and set the Margin
to 10 on all sides.
Hopefully the spacing looks great, with regards to the button Face
and Rim
, just like the example below:
Now this is fine for a 100x100 pixel button like ours. But I wonder what would happen if I changed the button size to 32x32 pixels. (Which is probably the lowest resolution worth displaying a stylised button in).
But rather than change the size of this button, I'm going to create copies of this Button Style. These copies will update dynamically, because they share the same Style
and Template
. So come out of the Button Template and Style using the Return Scope icon. Place two more buttons on the page, directly below the first. Set the sizes to 64x64 and 32x32 pixels, respectively.
We now need to tell the new buttons to use our Style
, that we named ButtonRound1
.
Right click on the middle button and select Edit Template > Apply Resource > "ButtonRound1".
Another way would be to go to the Resources tab, and inside [UserControl], select "ButtonRound1".
Drag this Style Resource onto your button, release the mouse, and select Style from the small popup window.
Things are not looking good for the two 2 smaller buttons, but fine on the largest. What is going wrong?
The Face
of the button is not spacing correctly within the Rim
, because of the Margin
s we set on the Face
. Go back in to the Button Template and select the Grid
named Face
. Change the Margin
s to 4 and review the results.
See how the Face
now fits correctly in the smallest button, but not in the biggest one. Setting a Margin
is definitive, and sets a fixed distance in pixels from its reference object (parent).
So Margin
s do not really work, as the Rim
and Face
do not reference each other, they both reference their parent.
Section 3 - Scalability Issues
Earlier, I said there are two ways to size your objects within Expression Blend, but there are a few more! All are used in conjunction with Auto Size, with Horizontal and Vertical Alignments set to Stretch
(the defaults). (So the child elements will Stretch
to respond to the instructions of the parent object.)
So to properly reference the Face
and the Rim
from each other, we will use a Scale Transform. Select the Grid
named Face
and Reset the Margin
s to 0
.
Just below the Margin
s in the Properties tab is a section called Transform; open this section if currently collapsed and select the Scale tab.
Now set the Scale for the X and Y axes to 0.8. The Face
is now sitting nicely within the Rim
at all three sizes.
You have probably noticed that we still have the black border on the Face
, called the Stroke
. It almost seems to get heavier and thicker as the button gets smaller. It doesn't, as it is exactly 1 pixel thick on all three buttons. But 1 pixel is a larger proportion of the button surface in the smallest button than it is in the biggest.
Select the Ellipse
named BGround1
in Objects and Timeline. Change the Stroke Thickness in the Appearance section of the Properties tab.
Give it a value of 4 and review your results.
The Stroke
does not scale and as such should be avoided most of the time, so let's get rid of it. We could set the Stroke Thickness to 0, but it's better to tell the Ellipse
to have No Stroke.
So firstly, Reset the Stroke Thickness to 1, as this keeps things tidy and the XAML cleaner. And with the Stroke
selected in the Brushes section of the Properties tab, select No Brush.
Let's get the ContentPresenter
out of our way as well, as it is just a distraction for the moment. To hide it at design time, go to Objects and Timeline and click the "Eye" icon next to the element. It will be visible at run time, which is OK, and not really what I want, so instead I will hide it at run time.
To do this, select the ContentPresenter
and in the Properties tab, change its Visibility
to Collapsed
.
Now let's start adding some depth to our button Face by adding another Ellipse
that sits over the top of BGround1
. Select the Grid
named Face
and double click the Ellipse icon in the left tool bar.
This will insert another Ellipse
with nice clean "Default" settings inside of the Grid
element named Face
. Select the Ellipse and rename it "FaceRadialGradient
". And for clarity, while we are at it, let's rename the Ellipse
named "BGround1
" to "FaceBGround
".
(Stay on top of naming your elements to prevent confusion and to help others reference them later.)
Now with the element FaceRadialGradient
selected, remove the Stroke
and set the Fill
to Gradient
(Radial
).
If your Gradient Stops are set as default, the Face
will look like mine below:
Now flip the Gradient Stops using the "Reverse Gradient Stops" icon to the right of the Radial Gradient icon.
Your button Face
should now look like this:
Now select the left Gradient Stop, set the Alpha
to 30%, and move to 75 on the Ribbon
.
Now select the right Gradient Stop and set the Alpha
to 50%.
Hopefully your button is starting to look better.
Now why did I bother to reverse the Gradient Stops earlier? (So Black was on the Right and White was on the Left.) Because the Tone
as well as the Transparency
(Alpha
) has an effect on the Gradient
of the Fill
(colour can be used in the Tone
, but this will reduce flexibility when changing colour schemes).
With the right Gradient Stop at 100 on the Ribbon
selected, change the colour from Black to White. Review the results:
With the Gradient Stop set to black, the edge of the Face
is looking fairly dark. And we could adjust the Tone
of the right Gradient Stop to a dark grey. But I also want to change the way the light hits our button. So we will access some seemingly hidden controls for the Gradient Brush. In the left hand tool bar, select the Gradient Tool. (Hopefully, you will now have an Arrow tool over the top of the button face.)
If you can't see the Gradient Tool, look in the Projection section of the Properties tab.
Make sure it is set to "Default" for your element and all its parent elements.
(Blend is unable to show the Gradient Tool when a Projection is set on an element, or on any of its parent elements).
There are a number of things we can do with the Gradient Tool, like adjusting the Gradient Stops.
But we are more interested in other options, like offsetting the centre and adjusting the size.
So click and drag on the stem of the Arrow
(Not near the Gradient Stops) and move upwards towards the left a little.
Now click on the head of the Arrow
to enlarge the scope of the gradient.
So that it just covers the lower right edge of the Face.
.
The Face now looks like it has the light source in the top left corner. at about 315% (360%-45%).
(Or 180% opposite to that, if you view that button as concave, rather than convex).
Things are starting to look nicer, but I'm still not happy about the spacing between the Rim
and the Face
.
It is OK in the largest button, but lost and almost non existent in the smallest.
It is proportionally correct, but not really what we want.
Ideally we want the Rim
spacing not to Scale
when we resize.
Or to be limited in some way, which we can do using Margins
.
So select the Face
element in the Objects and Timelines, and set a Margin
of 1
on all sides.
The button Face
has reduced in size by 1
pixel on all sides, for all 3 of the buttons.
Which has helped and has had very little affect on the largest button.
As 1
pixel is only 1%
on a button 100x100
pixels.
But 1
pixel is about 3%
on the 32x32
pixel button.
So we have combined 2 methods of controlling the size and relationship of the Face
and the Rim
to their parent.
A Scale Transform and a Margin
.
(One proportional to the scale of the object and another that is finite).
Now that the spacing is better, the Rim
needs to be a bit fatter.
So with the Face
element still selected, change the Scale Transform to 0.75
for both the X
and Y
axis.
Now select the Rim
element and edit the Opacity Mask in the Properties tab.
Change the Gradient Stops we set earlier, from 0
, 84
, 85
, to new locations on the Ribbon at 0
, 79
, 80
.
The Rim
should now have more of the inner visible.
We now need to update the gradient overlay for the Rim
, to span across the larger band we revealed.
So select the Ellipse
named "RadialGradient
" and while we are here, rename it "RimRadialGradient
".
Then do the same for the Ellipse
named "BGround
", renaming it "RimBGround
".
(This is neater and will be easier to reference later.)
Select the RimRadialGradient
element again.
And change the Gradient Stops of the Fill
, in the Properties tab to: 80
, 87.5
, 92.5
and 100
.
We now have a better proportioned button, with a fatter Rim
.
If you are wondering if we still need the Margins
to control the spacing of the Rim to the Face.
Try resetting the Margins
of the Face
element to 0.
If anything, a value of 2
could be better, so set the Margins
to that.
We will also get rid of the horrid red background.
It makes sense when designing, to ensure your UserControl
(Button) looks good on dark background, as well as a light background.
So come out of the Button Template, using the Return Scope icon.
Select all 3 buttons, and use Copy and Paste to duplicate 3 more, and moved them to the right.
Then place a Rectangle
with a black fill, higher up the tree in the Objects and Timelines and therefore behind the buttons.
(You are now fully in control, of how my button will look, in almost any situation!)
Time to make things pretty, now we have the bare bones of our button.
I want to apply a gradient on the Rim
, to mimic the lighting effect on the Face
.
Go back into your Button Template and select the RimRadialGradient
element.
In the Properties tab, select Opacity Mask and set a Linear
gradient.
Select the Gradient Tool in the left hand toolbar and set as shown below:
Set a Gradient Stop to 15
on the Ribbon
and the Alpha
of 50%
.
Then set a Gradient Stop to 85
on the Ribbon
and leave the Alpha
at 100%
.
(Tone
and colour is not relevant in an Opacity Mask, as only Transparency
is being affected).
Set the head and tail of the Gradient Tool to the corners of the bounding box to ensure a 45% angle.
But there is no point having the Gradient Stops at 0
and 100
on the Ribbon
.
(We can only apply the Opacity Mask to what is visible in the element).
So the top left of our Rim
, looks a little bit brighter than the bottom left.
But more contrast is required and it is not only the Opacity Mask that is determining how visible this element is.
Set the Opacity for the element in the Appearance section to 50%
.
But this only reduces the visibility and contrast of this element.
(Or layer - If you are thinking Photoshop!)
Instead look at the Fill
of the element, to see what we previously set.
The Gradient Stops at 87.5
and 92.5
on the Ribbon
, have an Alpha
of 60%
.
Change the Alpha
for both of these to 90%
.
Which helps, but we need to Reset the Opacity of this element back to 100%.
Which hopefully should give something looking like this:
Now there is plenty of contrast applied to our diagonal gradient Opacity Mask.
But we had to increase the contrast of the Fill
, to increase the contrast of the Opacity Mask.
The Fill
and Stroke
of an element, are the primary components, when it comes to the transparency of that element.
If the Fill
has an Alpha
of 50%
and the Opacity
of that element is only 50%
, then I will effectively only see 25%
of that element.
Even if I set the Opacity
of that element to 100%
, I can still only see 50%
of it, as that is controlled deeper, in the Alpha
value of the Fill
.
You might now be asking.
Why set the Alpha
values to 90%
and not 100%
and then set the overall Opacity
of that element to 90%
.
Will this give me the same results? In this example, almost none, but there is a difference!
With the Gradient Stops set to 90%
, rather than 100%,
I have slightly more influence over the Tone
.
Also I believe 90%
is the maximum value, I would ever want applied to this element.
So this way, I am prevented from exceeding this value, by setting the Opacity
above 90%.
Now our button Rim
is looking very shiny, and that might be enough for your purposes.
But it is not very realistic...
What it really needs, is for the Rim
to catch the light:
Only on the outer edge, in the top left corner.
And only on the inner edge, in the bottom right corner.
Something like the image below:
So how do we go about creating a more realistic light effect for a raised Rim?
Firstly, Reset
(remove) the Opacity Mask applied to the element RimRadialGradient
, as this is no longer needed.
This gives us an very bright looking Rim
, so set the Opacity
of RimRadialGradient
to 40%
.
This element (layer), will now provide just the basic contour/outline of the Rim
.
We will overlay 2
more Ellipses
to define our highlights.
Select the Rim
element and using the using the Ellipse
tool in the left hand tool bar.
Insert 2
new Ellipses
in the Grid
named Rim
, and remove the Stroke
on both Ellipses
.
Rename them "RimHighLightUpper
" and "RimHighLightLower
" respectively.
Click the "Eye
" symbol next to the RimHighLightUpper
element to hide it.
Now we can work on RimHighLightLower
, without RimHighLightUpper
getting in the way.
Select RimHighLightLower
and set a Radial Gradient Fill, with white Gradient Stops at 86
, 94
and 100
along the Ribbon
.
Set the Alpha to 0%
for all the Gradient Stops, except for the one at 94, which should be 100% Alpha.
Using the Gradient Tool, move and resize the gradient to look like this:
The gradient looks good on the bottom right inner edge.
But there is an unwanted highlight, on the inner edge at the top left.
So to get rid of this, let's apply an Opacity Mask, that only shows the part we want.
So set a Linear Gradient in the Opacity Mask as shown.
With Gradient Stops at 55 and 75 on the Ribbon and set the Alpha of each to 0% and 100% respectively.
That looks OK for the lower highlight, so hide this element and move on to the upper highlight.
Select the RimHighLightUpper
element and unhide it.
With the RimHighLightUpper
element selected, set the Fill to a Radial Gradient.
Now set white Gradient Stops of the Fill to 86, 92 and 100 along the Ribbon.
Set the Alpha to 0% for all the Gradient Stops, except the one at 94, which should be 100% Alpha.
Next apply an Opacity Mask, with a Linear Gradient, just as we did for the lower highlight.
With the Gradient Stops at 55 and 75 and the Alpha of each to 0% and 100% respectively.
(The only difference is, we are pointing the Gradient Tool head and tail in opposite directions).
Now select the Fill again, and with the Gradient Tool selected.
Offset and enlarge the gradient to look like the image below:
With that done, unhide the element named "RimHighLightLower
", and admire the efforts of your work!
The highlights are maybe a bit strong and need a bit of adjustment.
So set the element Opacity
of RimHighLightLower
to 70%
, and 80%
for RimHighLightUpper
.
Which I think concludes all we need to do for the Rim
of this button.
So let's go back to the Face
and see what we can do there.
Select the FaceRadialGradient
element, and in the Fill properties.
Change the Gradient Stops of the Radial Gradient to 40 and 100 on the Ribbon.
Set the Alpha values to 100% and 0% respectively, and position using the Gradient Tool as shown.
Now set an Opacity Mask with a Radial Gradient and Gradient Stops at 79 and 80 on the Ribbon.
Set the Alpha values to 0% and 100% respectively.
Hopefully your Artboard looks something like this:
Now the button is starting to really take shape, we have a nice looking Rim
.
And the Face
has an attractive border and Inner ready for us to get creative with.
So far, we have used Opacity Masks extensively to limit what is being shown in an element (Or layer).
But it makes no sense here to use an Opacity Mask to limit what is being shown.
As we would need to keep applying more Opacity Masks to my elements.
Just to preserve the Transparency and hence the background colour of the button.
But we don't need to worry about Transparency, as we are only showing the background colour.
And this is a Resource, that is set in the Style of the button (UserControl
).
So remove the Opacity Mask applied to FaceRadialGradient
.
Instead create a new Ellipse in the Face
element, name it "InnerBGround
".
Right click on the InnerBGround element and select Group Into > Grid.
Rename this Grid
to "Inner
" and ensure it is expanded to show its child elements.
Now change the Scale in the Transform section of the Properties tab to 0.8 for the X and Y axis.
Select the InnerBGround
element and remove the Stroke
.
Now select the Fill
property and in the Advanced Properties Option button, select Template binding > Background.
Now we have the same result as applying an Opacity Mask, to form the Inner
of our button Face
.
But with the freedom to start overlaying effects from the start, or using the Stroke
.
As well as re-adjusting or tweaking our layout, with regards its spacing at different sizes.
So select the Grid
named "Inner
" and set Margins 2 on all sides.
This helps enlarge the border of the Face
for the smallest sized button, just like we did for the Rim
.
Now add 2 more Ellipses in the element named Inner
.
Rename these "InnerEdgeShadow
" and "InnerGlossHighLight
", remove the Stroke
on both elements.
Now hide the InnerGlossHighLight
element and select "InnerEdgeShadow
".
Change the Fill to a Radial Gradient, with black Gradient Stops at 50 and 100 on the Ribbon.
Set the Alpha
values to 0%
and 100%
respectively.
Now change the Opacity
of the element (or layer) to 30%
.
Now unhide the element named "InnerGlossHighLight
" and select it.
Give it a Fill of Radial Gradient and white Gradient Stops at 49 and 50 on the Ribbon.
Set the Alpha
values to 100%
and 0%
respectively.
With the Gradient Tool selected, change the proportions of the gradient to match shown.
(You could set the Gradient Stops anywhere on the Ribbon and resize the Gradient Tool to suit.)
Now change the Opacity
of the InnerGlossHighLight
element to 50%
.
Then apply an Opacity Mask, with a Linear Gradient at Stops at 0 and 50 on the Ribbon.
Set the Alpha
values at 100%
and 0%
respectively.
Using the Gradient Tool, ensure the gradient looks like the image below:
Now we have pretty much recreated Timmy Kokke's Glass Orb Button.
The only real difference, is that I have not subdivided any Grids to control the proportions.
(Both methods are equally effective, it just depends on what you prefer and the circumstances, to define the best approach!)
Now let us rotate the InnerGlossHighLight
element with a Transform
, to give it the same highlight Angle
as the Rim
.
Select InnerGlossHighLight
and in the Transform section of the Properties tab, change the Rotation Angle to 45%.
(So what happened? The gloss highlight has disappeared.)
The problem is the Opacity Mask, which will only work correctly at Angles 0 and 180.
But to get around this, we will Reset the Rotation Angle back to 0 and instead apply a Projection.
So in the Projection section, (directly below) set the Z Rotation Angle to 45%.
Your buttons should now look like this:
Remember that I spoke earlier about the Gradient Tool not being visible on an element, when a Projection is being applied?
So select the element named "InnerGlossHighLight
" and try editing the Fill or Opacity Mask with the Gradient Tool.
The Gradient Tool is not accessible, or at least not in Blend 3, but who knows for future releases.
So just to prove my point, remove the Projection and see that the Gradient Tool is now visible.
Now there is just one more thing to change on this button, so with the Projection re-applied.
Select the RimHighLightLower
element and change the Opacity to 50%.
Now that should have reduced the highlight on the rim on the lower right hand side.
Feel free to get creative, and modify this button, but I'm happy with the look of it now.
Now we have an attractive button, it is time to breathe life into it, by adding some Interaction and Animation.
But firstly, we need to have something to animate, and we will start by adding a spot of colour.
Now because we have created the button with 3 basic components, a Rim
, a Face
and an Inner
, we can easily introduce an overlay to affect the colour of each of these components, so let's start with the inner
.
Ensure you are in the Button Template and have the Grid
element named "Inner
" selected.
Now insert a new Ellipse
and name it "InnerOverlayColour
".
Move it in the list of the Objects and Timeline to the position shown in the image.
Remove the Stroke of the InnerOverlayColour
element and set the Fill to bright red.
Now this looks a little bright and unrefined, so let us use an Opacity Mask (which appears to be my favourite tool!).
So set an Opacity Mask with a Radial Gradient and Gradient Stops at 25 and 100 on the Ribbon.
Set with Alpha values to 100% and 50% respectively.
That is better, but still a little bright, so set the Opacity to 90% for the InnerOverlayColour element.
Now we have a nice warm central glow, fading out to black at the edge.
This a combination of the Opacity Mask and the InnerEdgeShadow
element.
Try changing the Opacity
of InnerEdgeShadow
to 10%
and the Fill
of InnerOverlayColour
to Green
.
When you are happy, reset the Opacity
of InnerEdgeShadow
to 30%
.
To help you develop a nice colour scheme, set the Fill
of InnerOverlayColour
to Template Binding > BorderBrush.
Now go to the Style
of your button, by clicking on the icon, at the top left corner of the Artboard.
Ensure the Style is selected in the Objects and Timelines.
Now change the Background
and BorderBrush
colours of your Style
.
See how easy it is to edit the whole colour scheme of the button.
I'm going to use RGB values of 60, 50 and 0 for the Background and bright red for the BorderBrush
.
You may see the Style
has another colour brush, named "Foreground
" that we could Template Bind to.
And you might be wondering why we didn't use this one, rather than the BorderBrush
.
Well the Foreground
brush controls the colour of the ContentPresenter
, which is currently hidden.
And making the centre of the button, the same colour as the ContentPresenter
would mean one is not visible over the other.
So let us just leave things as they are.
We now need to decide, what will our button do?
During the various mouse states and how do we set these states?
Ensure you have the States manager tab open, in the top left area of the window.
You should see a list of CommonStates, consisting of Normal, MouseOver, Pressed and Disabled.
Above the CommonStates is the Base state and this state is applied as the default for all other states.
So let us set the Base state, to have NO red glow.
And as long as we have no Keyframes set, what we define here, will be reflected in all the other states.
This means that the Normal state, does not normally require any Keyframes.
As it is generally the same as the Base state.
So ensuring you are in the Base
state, select the InnerOverlayColour
element and set the Opacity
to 0%
.
Now select the MouseOver
state and set the Opacity
of the InnerOverlayColour
element to 50%
.
Then select the Pressed state and set the Opacity
of the InnerOverlayColour
element to 90%
.
Now run your application by pressing F5.
Hopefully, your button glows in the middle during MouseOver
, getting brighter when Pressed.
But it needs some refinement, as the transition from state to state is happening instantly.
It needs slowing down a bit, over a defined duration of time.
So set the Default Transition duration to 0.1 seconds.
Run your application and see the change.
(As the transition from state to state is so simple, only a very short duration is required).
(Setting too long a duration, makes the transition seem to lag).
What can we do next? Well, we could do a simple colour change to say green, when the button is Pressed.
But that would not be very smart, as about 10% of the population are red and green colour blind.
So let us introduce some motion instead and make the button Face
grow during MouseOver
and Pressed
.
Select the Face
element and with MouseOver
state selected.
Change the Scale Transform to 0.82 for both the X and Y axis.
Select the Pressed state and do the same as you did for the MouseOver
state.
Now run your application (F5).
Because we now have motion during the Transition
, from Normal
to MouseOver
.
The Opacity
we initially set for that Transition
seems a bit excessive.
So ensuring you are in the MouseOver
state, select the InnerOverlayColour
element and set the Opacity
to 30%
.
Now check your results and while you are there, look at the MouseOver
state on the smaller buttons.
The Face
does not grow to touch the edge of the Rim
, as it does in the largest button.
This is because of Margins
we set on the Face
element.
We can change the Margins
for different states, but they will not animate.
They will be applied at the end of the Transudation
duration, in one block, resulting in a jolty animation.
So we will not be setting up different Margins
for various states, as this will only give problems.
But we can make the Margins
work better, by tweaking them a little.
Change from the MouseOver
state to the Base
state.
And set the Margins
of the Face
element to 1
on all sides.
Run your application and see that the smaller buttons are functioning better now.
Now let us now add a bit of "pop" to our transition, by applying an Easing Function.
First, change the Transition
duration to 02.
seconds, then click on the small square to the left and select the EasingFunction "Back Out".
This will change the manner in how the Face
will Scale
, over a new duration of 0.2
seconds.
I have increased the duration, so that the Easing Function has more time to animate.
You may prefer to set the duration to 0.3
seconds, your choice!
Run the application, and test your button at various sizes.
The Face
should "pop" as it changes Scale
, and this will be applied to all the Keyframe
changes.
Now it is probably not normal, for someone to press a button, and to hold it Pressed.
But for demonstration, we will.
So let us set an animation, to loop during the Pressed
state.
Select the Pressed
state and the InnerOverlayColour
element.
Now open the Timeline
by clicking the Show Timeline icon.
Now in the Timeline
, set a Keyframe
at a duration 1.6
seconds, as shown in the image below.
(Use the Record Keyframe icon, or just make the change in the Properties tab to automatically generate one.)
Now move the Timeline
to 0.8
seconds and insert another Keyframe
.
Now change the Opacity
of the InnerOverlayColour
element to 50%
for this Keyframe
.
(We set the last Keyframe first, so that it copied the values from the Keyframe at duration 0 second.)
(This way our animation can loop, as the start and the end are the same.)
Now select the Pressed timeline in the Objects and Timeline, as shown in the image below:
In the Properties tab, select the RepeatBehaviour
and set to "Forever
".
Run your application, press and hold your button, and hopefully admire your glow and fade animation.
Now your glow and fade animation is changing in a linear manner, when it should be more like a sine curve.
We can set an EasingFunction
for each individual Keyframe
to mimic this.
Simply by clicking on each and setting the EasingFunction
in the Properties tab.
I will leave mine as they are, but feel free to play.
(I'm more interested in making the red glow, grow and shrink as it fades in and out.)
Which we could try and achieve by applying a Scale Transform.
But I already know this will not work very well.
As the edge transparency (Alpha
) of the InnerOverlayColour
element, is only set to 50%
in the Opacity Mask.
This means it will have a hard edge when I try to shrink and grow the element. Not very desirable.
As I mentioned earlier, the InnerEdgeShadow
element also controls the edge glow of the inner and it is this we will change.
So in the Pressed
state, select the InnerEdgeShadow
element and set an animation, for a duration of 1.6 seconds.
(Just as we did for the InnerOverlayColour element.)
Now at 0.8
seconds, set the Opacity
of the InnerEdgeShadow
element to 60%
.
And the Opacity
of the InnerOverlayColour
element to 70%
.
Run the application and test the results.
We now have a brighter central core and a darker edge to the inner glow.
Resulting in a more realistic electric light bulb glow and fade.
We can further emphasise this, by animating the Gradient Stops on the Fill
of the InnerOverlayColour
element over time.
So still in the Pressed
state and at a duration of 0.8
seconds.
Change the Gradient Stop
set at 50
on the Ribbon
, to 30
on the Ribbon
.
Test the application, and hopefully your button dims to a central core in the Pressed
state
(This hopefully may inspire you to create a Cyborg, or maybe Kit from Night Rider!)
Now let us animate some other parts of our button, like the Rim
.
So select the Base
state, in the States
manager.
Select the Rim
element and insert an Ellipse
within this element and rename it "RimOverlayColour
".
Remove the Stroke
, set the Fill
to Template Binding > BorderBrush
.
In the Objects and Timeline, position the RimOverlayColour
element, in front of the RimBGround
as shown.
Ensure the Opacity
of the RimOverlayColour
element, is set to 0%
in the Base
state.
Now in the MouseOver
state, set the Opacity
to 20%
and to 40%
for the Pressed
state.
In the Pressed
state, set an animation for a duration of 1.6
seconds, just like we have before.
Now at 0.8
seconds on the Timeline
, set the Opacity
of the RimOverlayColour
element to 0%.
Run your application.
Hopefully you will have a slight red hint on the Rim
during MouseOver
and a stronger glow and fade during Pressed
.
Now at the risk of going overboard, let us Scale
the Rim
to pulse in size, during the Pressed
state.
In the Pressed
state, select the Rim
element and set up an animation just as we have before for 1.6
seconds.
Now go to the Keyframe
at 0.8
seconds and set a Scale Transform
for the Rim
element,
by changing both the X
and Y
axis vales to 1.05
.
Run your application and see how the Rim
now seems to breathe, even if it may be a little over the top!
(I will leave you to fine tune the animation with the EasingFunction,
for each Keyframe
).
This is just an exercise and why I committed, what could be considered a cardinal sin!
By increasing the Scale
of the Rim
to more than 1
.
As the Rim
will now sit outside of its boundaries when Pressed
and may overlap with other objects on the page.
But as I only increased the Rim
Scale
a tiny amount, from 1
to 1.05,
I think it would be OK and could leave it.
Or in the Base
state, resize the 3
main parts of my button (the Rim
, the Face
and its Inner
).
As well as All
the Scale
animation Keyframes
we have set.
But a quick and dirty way to compensate, is to Scale
the parent object of all 3
parts of the button.
So select the element named "[Grid]
" in the Objects and Timelines
.
(I have collapsed the tree for clarity in my image).
Now set a Scale Transform
for both the X
and Y
axis of 0.95
.
(This will compensate for the 1.05
Scale
of the child object).
You can leave this correction if you like, but I'm going to remove it.
As I am certain that this UserControl
, will always have more space (Padding
) around it, than our animation will encroach.
Now we have one last change to make for the 3
main States
of the button.
So select the RimHighLightLower
element and in the MouseOver
and Pressed
state, set the Opacity to 30%
.
This gives a slight hint that when the button Face
grows in size.
It blocks some of the light from hitting the inner lower edge of the Rim
.
That is all I will do with regards to animating this button.
But please feel free to enhance it further, by maybe animating the border area of the Face.
During the previous section on animating our button, we only applied one colour state to our button.
Now there is nothing to stop you animating the Fill
of an Ellipse.
And therefore, changing the colour of a button for different state.
This is unless:
The colour you are using is Data Bound
.
And in this case, Template Bound
to the BorderBrush
in the Style
of our UserControl
(Button).
We cannot change this Style Resource
over time, as it is outside of our control and would make no sense to do so anyway.
(It would change the colour of every object, item and element, that references this Resource
, probably the whole page/application!)
Instead, we will add more Ellipses
to our UserControl
(Button).
So ensure you are in the Button Template
and in the Base
state.
Select the Grid
element named "Inner
", insert and position a new Ellipse
named "InnerOverlaySecondColour
" as shown.
Remove the Stroke,
set the Fill
to bright purple (RGB 255, 0, 255
) and the Opacity
of the element to 90%
.
Now set an Opacity Mask
, just like you did for the Template Bound
element InnerOverlayColour
.
So select InnerOverlayColour
and select the Opacity Mask
.
Now click on the Advanced Properties
button and select "Convert to New Resource
".
In the Popup window, name your Brush Resource
"ColourMask
" and press OK
.
Now go back to the InnerOverlaySecondColour
element and select the Opacity Mask
.
Click on the "Brush Resources
" tab and select "ColourMask"
from the Local Brush Resources
.
Now the bright purple is toned down, let's animate the Fill
of this element.
Select the MouseOver
state and change the Fill
to bright green.
Now we want to remove the Scale Transform
we applied earlier.
To the Face
element,
during the MouseOver
state.
So still in the MouseOver
state, select the "RenderTransform
" applied to the Face
element in the Objects and Timeline and hit delete.
The button now shrinks to Scale
values of 0.75,
for both the X
and Y
axis.
These are the values set in the Base
state and hence the default for our button.
(But resetting the values of the Scale Transform in the Properties tab, would yield different results, the scale would reset to 1.0, not what we want!)
(Expanding the tree to reveal all operations applied to an element, this can reveal any unwanted, or unneeded animation Keyframes
)
Now that the button is smaller compared to the Rim
, in the MouseOver
state.
We should also reinstate the lower inner highlight on the Rim
, back to the Base
state.
So repeat the process to remove an element Keyframe
, (this time, it is the Opacity
you need to delete).
And once again for the Opacity
of the InnerOverlayColour
element.
Next, ensure you have the InnerOverlaySecondColour
element selected.
Go to the Pressed
state and set the Opacity
to 0%
.
Run your application and review that result.
Hopefully, your button changes from purple, to green, to red.
Notice how when the colour changes, it seems to blink in the middle, let us investigate.
Set the Default transition to 2.0
seconds and run the application again.
Hopefully you can see that as the Opacity
of one colour decreases, the Opacity
of the other increases.
This leaves a dead spot in the middle of the animation, that is not filled by the changing colours.
I am not unhappy with this effect, as long as the timing is adjusted correctly.
(There are ways to modify this behaviour, but don't want to get carried away here.)
Look at the EasingFunction
of the Default transition.
Which we set as "Back Out", to give a "pop" action to our Scale Transform.
Look at the profile of the curve, to see how it affects the animation.
From a starting point of zero, the curve ramps up steeply, peaking well above 100%
and settles back down to 100%
.
We can change how emphasised the peak is beyond 100%
, by changing the Amplitude
.
Also, this EasingFunction
profile reaches 100%
, in almost the first quarter of the duration.
It is not helping with the colour change and us setting a suitable duration.
So remove the EasingFunction
and set the Default transition to 0.5
seconds.
Run the application again, notice how the duration of the colour change is about the same.
(One quarter of the time, without the EasingFunction
that reaches 100%
in roughly one quarter of its profile).
Now change the Default transition to 0.3
seconds, as I think that is about right.
Next, we will adjust the MouseOver
state, to better suit our evolving button.
Select the Rim
element and set a Scale Transform in both the X
and Y
axis of 1.05
.
Now run your application and see what you think.
(I spoke earlier about colour blindness, so I have ensured a clear geometric change between MouseOver
(Green) and Pressed
(Red).)
Now there are lot more things we can animate, but I will leave these to you, but here are some suggestions:
- Set lowlights on the opposite edges of the
Rim
to the highlights. - Animate the lower highlight
Opacity
in the Pressed
state, to match the Rim
grow and shrink. - You could also set the border area of the
Face
, to glow red in the Pressed
state to match the Rim
glow.
Essentially do anything you like, use your creativity, there is no right or wrong, just personal taste.
Have a look at different EasingFunctions
, play with the state to state transitions as well.
If you are coming from a graphical background.
You have probably never had to produce artwork, taking things like Focused
into account.
Focused
is a graphical way to indicate to the user, what Control
on the screen is currently selected, or has the focus of the Tab
control.
The Focused
state could be decorate, but this is not recommended.
As it should be common and uniform to all your Controls
and its primary role is an aid, not a toy.
(But that is my opinion and as I have no intention of designing a focused style for all the controls I might need).
Ensuring you are in the Base
state, select the element named Grid
and insert a new Ellipse
named "FocusVisualElement
".
Remove the Fill
and with the Stroke Thickness set to 1
, change the colour to (RGB 109, 189 and 209
).
Now in the Base
state, select the Opacity
and set it to 0%
.
Then select the Focused
state and set the Opacity
to 100%
.
Now select the Base
state again and click on the eye icon to the left of the Focused
state.
This allows us to work in the Base
state and not set any Keyframes
that define a change from the Base
state.
But most importantly, see the Focused
state and elements, that are invisible in the Base
state.
Now run your application, select the button to give it Focus
and test the Normal
, MouseOver
and Pressed
states.
You should hopefully have a blue ring around the edge of your button, but like mine, does not animate with the rest of my button.
So move the FocusVisualElement
element, to inside the Grid
element named Rim
.
Now run your application, and see that the Focus
now follows the animation applied to the Rim
.
But it is not as clear as it could be (in my opinion), as it is placed over the top of the outer edge of the Rim
.
(In a default button, the Stroke
ring is just inside the edge of the button, but here I will set it outside.)
So with the FocusVisualElement
element selected and in the Base
state, set the Margins
to -1
on all sides.
This helps give the Focus
a bit of clearance, just in case the colour scheme matches the Focus
colour.
Run the application to review the results.
You might be thinking that we could put the Focus
, between the Rim
and the Face
of the button.
But we have set an Opacity Mask
to the Rim
, so if we want the Focus
to be visible in this area, we need to do some work.
As I see it, we have 3
immediate options, but I will leave you to ponder these.
I am happy with the Focus as it is, so I will move on.
Disabled
We also need to define a state for Disabled
, which generally partially blanks out all the parts of the Control
.
And as there are 2
parts to our button, we need 2
elements to blank it out.
As we don't want to influence the transparent part of our Control
.
Start with the Rim
and in the Base
state, place a new Ellips
e in the element named Rim
.
Rename this new Ellipse
"DisabledVisualElement
", remove the Stroke
and ensure the Fill
is white.
Now set the Opacity
to 0%
in the Base
state and to 55% in the Disabled
state.
(55%
is the setting used in a default Button.)
Now back in the Base
state, insert a new Ellipse
in the element named Face
.
Rename it "FaceDisabledVisualElement
" and position as shown.
In the Base
state, set the Opacity
to 0%
and in the Disabled
state to 55%
.
Hopefully, your button should look like this in the Disabled
state.
Content
Because of the visual style of this button, it is un-likely we would want any content in the button.
Be it an Image
, an Icon
, or a ContentPresenter
.
But we should make some provision for the ContentPresenter
, in case it is needed.
Select the ContentPresenter
element and in the Base
state, change the Visibility from Collapsed to Visible.
Now hopefully your buttons will look like this:
Run the application and see that the Scale
of the ContentPresenter
does not follow the Scale
of the button Face
.
This may be Ok for you, but I would like it to track the Scale
of the button Face
.
So move the ContentPresenter
inside the element named Face
.
The text is now smaller, as shown in the image below, but will grow along with the Face
.
The animation change is hardly noticeable in the running application, as the text is too small and difficult to visually reference.
It is not realistic to presume the text will work in the smallest button, so making the text smaller to fit, would just be stupid!
And we don't really want to try and Scale
the text, to fit at all possible button sizes.
We also need to remember that by placing the ContentPresenter
in the Face.
The Scale
of the text is being reduced by 0.75
or 75%,
of the size defined by the Style
.
So should be edit the Font Size
in the Style
?
Or should we change the Scale
of the ContentPresenter
in the Button Template
?
We should change the Scale
of the ContentPresenter
in the Button Template
and not the Font Size
in the Style
.
This is because, when we apply this Style
to objects on your page, the Font Size
will match in Scale
to other objects on the page.
(If we set a Font Size
of 11
in the button Style
and did the same for a textbox Style
, we would want them the same size on the page, not 75% of that
)
So let us compensate for the Scale Transform
, that we automatically applied of 0.75.
When we placed the ContentPresenter
in the element named Face
.
Select the ContentPresenter
and while in the Base
state, set a Scale Transform
for both the X
and Y
axis of 1.25
.
This will bring the Font Size
back inline with the default settings of the button Style
and comparable with the Styles
of other Controls
.
Now go to the Style,
by clicking on the Style
icon at the top left of the Artboard.
Ensure your the Font Size
is Reset
to the default of 8.25
.
Hopefully, the text on your buttons will be the same scale as mine.
Which look fine in Expression Blend
, but the Text
is still very small when run in a web browser.
So it is fair to say, that in this UserControl
(Button).
Where text is overlaid on a graphical component, it needs to be bigger to make it clear.
Now we could again increase the Scale
of the ContentPresenter
, but not this time.
Instead, we should increase the Font Size
in the Style.
So that it is preset within the Style
, as the recommended minimum for this UserControl
.
When we apply this Style
to any button, the Font Size
will change to our preset (unless we override it) and suitably adjusted for this UserControl
.
So change the Font Size
to 11
in the Style
, run the application and decide for yourself.
Now a text string (or word), is not really suitable for the smaller button sizes.
So come out of the Style
for the button by clicking on the "Button" icon (Or Return Scope
icon).
Select the smallest button and in the Common Properties of the Properties tab, Reset
the Content.
(Notice that the default Font Size
is 11
and this is because it is set in the underlying Style)
Next select the medium sized button, change the Content
to "8"
and the Font Size
to 24
.
Then do the same for the buttons on the dark background.
Now hopefully your buttons look like this, when displayed in a web browser.
And that I think is the end!
Here is the source code for the completed button with the three recommended updates.
Even though, I would rather you built it yourself!
Summary
I hope you found this tutorial educational, as I have attempted to keep it as linear and un-repetitive as possible.
But at the same time, learning from our mistakes, adjusting as we need, to get the best from our layout capabilities.
Really what I want, is for your creativity to take over and to take the path I have shown.
I'm not saying it is the only path, so post a tutorial yourself, if you can add constructively.
Let me know if you would like more tutorials, for some of the other button Styles
shown in the Introduction.
Other Tutorials
And one last thing, please please please rate my articles! :-)
History
- 11th March, 2010: Initial version