Recipe 6.5.
Creating Simple Buttons
Problem
You
want to create an interactive
button that enables a user to click and perform an action, such as
submitting a form or calculating a total.
Solution
Create an instance of the SimpleButton class and create
display objects for upState, downState, overState, and hitTestState. Alternatively,
create a subclass of SimpleButton that describes your
desired button behavior.
Use the click event to invoke a method
whenever the user presses the button.
Discussion
The display list model provides an easy way to
create buttons through the SimpleButton class. The
SimpleButton class allows a user to interact with the
display object using their mouse, and makes it easy for you to
define that interaction through various button states. The possible
button states, listed here, are available as properties of the
SimpleButton class:
upState
-
A display object for the default "up" state of
the button. The "up" state is shown whenever the mouse is not over
the button.
overState
-
A display object that determines what the button
looks like when the mouse moves over the button. When the mouse
leaves the button area, the button moves back to the "up"
state.
downState
-
A display object that's shown when the button is
pressed (or clicked) "down". When the button is in the "over"
state, the "down" state displays when the user presses the left
mouse button.
hitTestState
-
A display object that defines a button's bounds.
When the mouse moves inside of the button's hit area, the button
enters the "over" state. The hitTestState is typically set
to the same display object as the upState. The
hitTestState is never actually displayed on-screen; it is
only used for mouse tracking purposes.
A button's state is handled by the
SimpleButton class, and is based on movement of the user's
mouse. You don't have control over setting the internal button
state (up, down, or over). Rather, you can only control which
display object should appear when the button is in a particular
state. By setting the state properties to different display
objects, you can provide feedback to the user as they interact with
the button using their mouse.
The following example creates a new
SimpleButton instance and defines button states using the
four state properties defined earlier. Because each state property
of the button needs to be set to a DisplayObject instance, the
helper method createCircle( ) is used to create
different colored circle shapes to be used for the various button
states:
package {
import flash.display.*;
import flash.events.*;
public class SimpleButtonDemo extends Sprite {
public function SimpleButtonDemo( ) {
// Create a simple button and configure its location
var button:SimpleButton = new SimpleButton( );
button.x = 20;
button.y = 20;
// Create the different states of the button, using the
// helper method to create different colors circles
button.upState = createCircle( 0x00FF00, 15 );
button.overState = createCircle( 0xFFFFFF, 16 );
button.downState = createCircle( 0xCCCCCC, 15 );
button.hitTestState = button.upState;
// Add an event listener for the click event to be notified
// when the user clicks the mouse on the button
button.addEventListener( MouseEvent.CLICK, handleClick );
// Finally, add the button to the display list
addChild( button );
}
// Helper function to create a circle shape with a given color
// and radius
private function createCircle( color:uint, radius:Number ):Shape {
var circle:Shape = new Shape( );
circle.graphics.lineStyle( 1, 0x000000 );
circle.graphics.beginFill( color );
circle.graphics.drawCircle( 0, 0, radius );
circle.graphics.endFill( );
return circle;
}
// Event handler invoked whenever the user presses the button
private function handleClick( event:MouseEvent ):void {
trace( "Mouse clicked on the button" );
}
}
}
After running the preceding code block, a green
circle appears in the movie. When you move your mouse over the
green circle, a slightly bigger white circle appears as a rollover.
When you click the white circle, it turns into a slightly smaller
gray circle. This visual effect is created by the
SimpleButton instance changing its state based on the
actions of your mouse, switching between the display objects
defined in the four state properties.
To listen for events from the button instance, the
addEventListener( ) method is used as described in Recipe
1.5. The click event, specified with MouseEvent.CLICK, is handled in
the preceding code by the handleClick( ) method. Anytime the
user clicks the button instance, the handleClick( ) method is
invoked, allowing certain actions to take place. In this simple
example, a short message ("Mouse clicked on the button") is
displayed to the console.
The
hitTestState property is perhaps the most interesting of
the button's state properties. You'll notice that the preceding
code sets the hitTestState to be the same display object
that defines the upState. It is typical to do this because
buttons should be activated when the user's mouse is within the
bounds of the upState display object.
|
Although the hitTestState is never
visible, failure to set the hitTestState to a display
object results in a button that can't be interacted with. Always
remember to set the hitTestState of your
SimpleButton, even if you simply set it to the same value as
upState.
|
|
The hitTestState can be set to any
display when you'd like to control the active bounds of a button.
To create a larger hit area for the button, try modifying the
previous code segment to set the hitTestState via this
line:
button.hitTestState = createCircle( 0x000000, 50 );
When running this example, you'll notice that
the button displays the white "over" circle before the mouse even
enters the area of the green circle, contrary to previous behavior.
This is because the hit area was increased to a circle of radius
50, giving a larger target area for the user's mouse. You might
also notice that black (0x000000) was specified as the
color for the hit area circle. This was done on purpose to
reinforce the fact that the hit area display object is never
visible.
An alternate approach to creating a
SimpleButton and setting the four display states for every
button is to create a subclass of SimpleButton that defines
your button's visual style and creates instances of that instead.
Recipe
6.4 describes how to create new visual classes. Following this
technique, you can create your own version of a
SimpleButton, making it easier to add multiple buttons to
your movie.
The following code creates a new
RectangleButton class. The RectangleButton class
defines the behavior for a special type of SimpleButton that
draws a green rectangle with some text on top of it:
package {
import flash.display.*
import flash.text.*;
import flash.filters.DropShadowFilter;
public class RectangleButton extends SimpleButton {
// The text to appear on the button
private var _text:String;
// Save the width and height of the rectangle
private var _width:Number;
private var _height:Number;
public function RectangleButton( text:String, width:Number, height:Number ) {
// Save the values to use them to create the button states
_text = text;
_width = width;
_height = height;
// Create the button states based on width, height, and text value
upState = createUpState( );
overState = createOverState( );
downState = createDownState( );
hitTestState = upState;
}
// Create the display object for the button's up state
private function createUpState( ):Sprite {
var sprite:Sprite = new Sprite( );
var background:Shape = createdColoredRectangle( 0x33FF66 );
var textField:TextField = createTextField( false );
sprite.addChild( background );
sprite.addChild( textField );
return sprite;
}
// Create the display object for the button's up state
private function createOverState( ):Sprite {
var sprite:Sprite = new Sprite( );
var background:Shape = createdColoredRectangle( 0x70FF94 );
var textField:TextField = createTextField( false );
sprite.addChild( background );
sprite.addChild( textField );
return sprite;
}
// Create the display object for the button's down state
private function createDownState( ):Sprite {
var sprite:Sprite = new Sprite( );
var background:Shape = createdColoredRectangle( 0xCCCCCC );
var textField:TextField = createTextField( true );
sprite.addChild( background );
sprite.addChild( textField );
return sprite;
}
// Create a rounded rectangle with a specific fill color
private function createdColoredRectangle( color:uint ):Shape {
var rect:Shape = new Shape( );
rect.graphics.lineStyle( 1, 0x000000 );
rect.graphics.beginFill( color );
rect.graphics.drawRoundRect( 0, 0, _width, _height, 15 );
rect.graphics.endFill( );
rect.filters = [ new DropShadowFilter( 2 ) ];
return rect;
}
// Create the text field to display the text of the button
private function createTextField( downState:Boolean ):TextField {
var textField:TextField = new TextField( );
textField.text = _text;
textField.width = _width;
// Center the text horizontally
var format:TextFormat = new TextFormat( );
format.align = TextFormatAlign.CENTER;
textField.setTextFormat( format );
// Center the text vertically
textField.y = ( _height - textField.textHeight ) / 2;
textField.y -= 2; // Subtract 2 pixels to adjust for offset
// The down state places the text down and to the right
// further than the other states
if ( downState ) {
textField.x += 1;
textField.y += 1;
}
return textField;
}
}
}
Because all of the button drawing is
encapsulated into its own reusable class, creating new button
instances is much easier. Instead of having to create a
SimpleButton and define the button states by hand for each
instance, you can simply create a new RectangleButton
instance and add that to the display list.
The following example shows how to create three
different rectangular buttons using this new instance:
package {
import flash.display.*;
public class SimpleButtonDemo extends Sprite {
public function SimpleButtonDemo( ) {
// Create three rectangular buttons with different text and
// different sizes, and place them at various locations within
// the movie
var button1:RectangleButton = new RectangleButton( "Button 1", 60, 100 );
button1.x = 20;
button1.y = 20;
var button2:RectangleButton = new RectangleButton( "Button 2", 80, 30 );
button2.x = 90;
button2.y = 20;
var button3:RectangleButton = new RectangleButton( "Button 3", 100, 40 );
button3.x = 100;
button3.y = 60;
// Add the buttons to the display list so they appear on-screen
addChild( button1 );
addChild( button2 );
addChild( button3 );
}
}
}
See Also
Recipes
1.5,
6.1,
6.4,
and 6.8
|