How to use the Feathers Button
component
The Button
class displays a touchable button. It can display an optional label and an optional icon with a variety of layout options. Buttons have states for each of the different touch phases and the skin, label, and icon can all be customized for each state.
The Basics
First, let's create a Button
control, give it a label, and add it to the display list:
var button:Button = new Button();
button.label = "Click Me";
this.addChild( button );
If we want to know when the button is tapped or clicked, we can listen for Event.TRIGGERED
:
button.addEventListener( Event.TRIGGERED, button_triggeredHandler );
This event is dispatched when the touch ends and the touch was not dragged outside of the button's bounds. In other words, the button is only triggered when the touch both begins and ends over the button.
The listener function might look like this:
function button_triggeredHandler( event:Event ):void
{
trace( "button triggered" );
}
Skinning a Button
A number of skins and styles may be customized on a button, including the background skin, the label text format, and the icon. For full details about what skin and style properties are available, see the Button
API reference. We'll look at a few of the most common properties below.
Background Skins
We'll start the skinning process by giving our button appropriate background skins.
button.defaultSkin = new Image( myUpTexture );
button.downSkin = new Image( myDownTexture );
Above, we add background skins for a couple of different states. The defaultSkin
is a skin that is used for any state where a specific skin isn't provided. We provided a skin for the down state, using the downSkin
property, and that will take precedence over the default skin when the button is pressed down. However, other states like up and hover don't have skins, so they'll use the default skin. If we wanted to, we could provide an upSkin
and a hoverSkin
for these states. The skin for the up state of a button almost always makes a good defaultSkin
.
For a button that can be disabled, we can provide a disabledSkin
too.
See the Advanced Skinning section below for additional button skinning techniques that can be used for optimized performance.
Labels
Next, let's ensure that the text is displayed. By default, Feathers uses Starling's bitmap font capabilities.
To style the text, we pass in a BitmapFontTextFormat
which allows us to pass in a BitmapFont
instance or a String name for a BitmapFont that has been registered with TextField.registerBitmapFont()
.
button.defaultLabelProperties.textFormat = new BitmapFontTextFormat( myBitmapFont );
Notice that we refer to defaultLabelProperties
in much the same way that we refer to defaultSkin
above. Just like with skins, labels may be styled differently depending on which state the button is in. If you want all states to use the same label styles, then you only need to pass your properties to defaultLabelProperties
. Label styles for other states, like downLabelProperties
exist too. See the Button
documentation for full details.
If you don't want to use bitmap font rendering, and you'd prefer to use Flash's traditional font rendering for device or embedded fonts, you can tell Feathers to use the TextFieldTextRenderer
instead. This renderer can use the classic flash.text.TextFormat
. For more information about using device or embedded fonts, see the Text Renderers tutorial.
Icons
Finally, let's add an icon to the Button
. Icons may be customized for all states, but let's simply use one icon.
button.defaultIcon = new Image( myIcon );
button.iconPosition = Button.ICON_POSITION_TOP;
Again, the Button
class provides a default option to supply an icon for all of the button's states, the defaultIcon
property. Icons for all other states, like downIcon
and hoverIcon
are available too.
We also set the iconPosition
property so that the icon appears above the label. We can position the icon to the top, right, bottom, or left of the label. There are various other useful layout options too:
button.gap = 10;
button.horizontalAlign = Button.HORIZONTAL_ALIGN_CENTER;
button.verticalAlign = Button.VERTICAL_ALIGN_MIDDLE;
The gap
refers to the space, measured in pixels, between the icon and the label. The horizontalAlign
and verticalAlign
properties will adjust the alignment of the icon and label inside the button, allowing you to anchor them at the edges or in the center.
See the Advanced Skinning section below for additional techniques to optimize performance when providing multiple icons to a button.
Targeting a Button
in a theme
If you are creating a theme, you can specify a function for the default styles like this:
getStyleProviderForClass( Button ).defaultStyleFunction = setButtonStyles;
If you want to customize a specific button to look different than the default, you may use a custom style name to call a different function:
button.styleNameList.add( "custom-button" );
You can specify the function for the custom style name like this:
getStyleProviderForClass( Button )
.setFunctionForStyleName( "custom-button", setCustomButtonStyles );
Trying to change the button's styles and skins outside of the theme may result in the theme overriding the properties, if you set them before the button was added to the stage and initialized. Learn to extend an existing theme to add custom skins.
If you aren't using a theme, then you may set any of the button's properties directly.
Advanced Skinning
For optimal performance, the same display object may be shared among different button states while simply changing properties. For instance, you might want to share a starling.display.Image
instance between multiple states while changing the value of texture
property, or maybe you'd prefer to use a Feathers ImageLoader
instance and simply change the value of the source
property.
When using this technique, the standard defaultSkin
, downSkin
, and similar properties are ignored. Instead, the Function
passed to the stateToSkinFunction
property is always used. This function has the following signature:
function( target:Button, state:Object, oldSkin:DisplayObject = null ):DisplayObject
This function receives the Button
instance, the current state, and the skin used for the button's previous state.
The following state constants are used by the Button
class:
The old skin passed in as the final argument may be null
. If so, a new skin must be created. If it is not null
, and its datatype matches the expected datatype, then it may be reused. If it's a different datatype, then a new skin must be created.
Let's look at an example of a simple stateToSkinFunction
implementation:
function( target:Button, state:Object, oldSkin:DisplayObject = null ):DisplayObject
{
var skin:ImageLoader = oldSkin as ImageLoader;
if( !skin )
{
skin = new ImageLoader();
}
switch( state )
{
case Button.STATE_DISABLED:
{
skin.source = disabledButtonSkinTexture;
break;
}
case Button.STATE_DOWN:
{
skin.source = downButtonSkinTexture;
break;
}
case Button.STATE_HOVER:
{
skin.source = hoverButtonSkinTexture;
break;
}
default:
{
skin.source = upButtonSkinTexture;
}
}
return skin;
}
In the example above, the button skins are ImageLoader
components. If the old skin is an ImageLoader
, it is reused. If it is null
or another datatype, then a new ImageLoader
is created. The source
property is updated to use a different starling.textures.Texture
instance depending on the value of the Button
instance's current state.
Skin Value Selectors
The SmartDisplayObjectStateValueSelector
class provides an implementation of stateToSkinFunction
that smartly selects the correct display object based on the values passed in. For instance, if you pass in a Texture
instance, it will return an Image
as the skin. If you pass in a Scale9Textures
object, it will return a Scale9Image
as the skin. If you pass in a Scale3Textures
object, it will return a Scale3Image
as the skin. Finally, if you pass in a uint
color value, it will return a Quad
as the skin.
The following SmartDisplayObjectStateValueSelector
provides an implementation similar to the example above.
var skinSelector:SmartDisplayObjectStateValueSelector = new SmartDisplayObjectStateValueSelector();
skinSelector.defaultValue = upButtonSkinTexture;
skinSelector.setValueForState( downSkinTexture, Button.STATE_DOWN );
skinSelector.setValueForState( hoverSkinTexture, Button.STATE_HOVER );
skinSelector.setValueForState( disabledSkinTextures, Button.STATE_DISABLED );
button.stateToSkinFunction = skinSelector.updateValue;
Simply pass a reference to the updateValue
function to the button's stateToSkinFunction
property.
In your own custom stateToSkinFunction
, you could even provide skins for states when the button is focused (if you're making a desktop app and the focus manager is enabled) by using button.focusManager.focus == button
.
Icons
Similar to stateToSkinFunction
, button also provides stateToIconFunction
to share a display object between multiple states for the button's icon.