Skinning Feathers components

All core Feathers components are designed with many styling properties to support a variety of custom designs. Many components include properties to set background skins for different states, different layout options like padding and alignment, and font styles. Additionally, some components have different options that allow them to behave differently depending on whether you're building a mobile or desktop app.

For practical reasons, Feathers components don't have default skins. Developers are encouraged to design unique skins for their games and applications. However, a number of example themes are included with Feathers that provide pre-created skins in several different styles. These themes may be extended to provide custom skins, if needed.

The Basics

All skins, layout options, and other styles available on Feathers components are exposed as public properties. Styling a component is as simple as setting these properties.

Let's look at a simple example of skinning a Button component:

var button:Button = new Button();
button.label = "Click Me";
button.defaultSkin = new Quad( 100, 30, 0xc4c4c4 );
button.fontStyles = new TextFormat( "Helvetica", 20, 0x3c3c3c );
this.addChild( button );

In the code above, we set the defaultSkin property provides the button with a background skin. In this case, we created an instance of starling.display.Quad class, which makes our background skin a simple colored rectangle. We could just as easily use starling.display.Image class to display a texture instead, and Feathers offers more advanced skinning options that we'll look at in a moment.

We set the fontStyles property to tell the button which font family to use for its text, along with the size and color. The starling.text.TextFormat class can be used to customize the font styles of any Feathers component, whether you are using bitmap fonts, embedded fonts, or system fonts.

Skin components with multiple states

Some components, like Button and TextInput have multiple different states, and it's possible to change a component's appearance when its state changes. For instance, we might change the background skin or font styles of a button when it is pressed and changes to the "down" state.

Display different textures for each state

Let's use the feathers.skins.ImageSkin class to change the appearance of the button's background skin when the state changes:

var skin:ImageSkin = new ImageSkin( upTexture );
skin.setTextureForState( ButtonState.DOWN, downTexture );
button.defaultSkin = skin;

Pass the default texture to the ImageSkin constructor. This texture will be used when the button isn't being pressed. Then, call setTextureForState(), and pass in the name of the state to customize, along with another texture. In this case, we specify ButtonState.DOWN for the name of the state.

It's possible to specify different textures for many different states, like in the following example:

var skin:ImageSkin = new ImageSkin( upTexture );
skin.setTextureForState( ButtonState.DOWN, downTexture );
skin.setTextureForState( ButtonState.HOVER, hoverTexture );
skin.setTextureForState( ButtonState.DISABLED, disabledTexture );
button.defaultSkin = skin;

Use different font styles for each state

Similar to how we can change the appearance of a button's background skin when the button's state changes, we can also change the font styles too:

var upFontStyles:TextFormat = new TextFormat( "Helvetica", 20, 0x3c3c3c );
var downFontStyles:TextFormat = new TextFormat( "Helvetica", 20, 0xff0000 );

button.fontStyles = upFontStyles;
button.setFontStylesForState( ButtonState.DOWN, downFontStyles );

In the code above, we set the fontStyles property to specify the default font styles for the text. Then, we call setFontStylesForState() with the name of the state and another starling.text.TextFormat instance.

Skin components with sub-components

Some complex Feathers components contain other components as children. For example a Panel container has a header. Sub-components like the panel's header may be styled, but their properties are not exposed directly on their parent component.

The easiest way to style a sub-component is to customize the factory function that the parent component calls to create the sub-component. The panel's header is created in its headerFactory:

var panel:Panel = new Panel();
panel.headerFactory = function():IFeathersControl
{
    var header:Header = new Header();
    header.backgroundSkin = new Quad( 200, 50, 0x3c3c3c );
    header.fontStyles = new TextFormat( "Helvetica", 20, 0xd4d4d4 );
    return header;
};
this.addChild( panel );

If you're using a theme, you may prefer to keep all of your styling code inside the theme. In this case, you should not use the sub-component's factory. Instead, consider creating a new style name for the sub-component and move your code into the theme.

A complex component will have a property to allow you to customize the style name of a sub-component. In the case of a Panel, we'll set the customHeaderStyleName property:

var panel:Panel = new Panel();
panel.customHeaderStyleName = "custom-panel-header";
this.addChild( panel );

Inside the theme, create a new function to style your sub-component:

private function setCustomPanelHeaderStyles( header:Header ):void
{
    header.backgroundSkin = new Quad( 200, 50, 0x3c3c3c );
    header.fontStyles = new TextFormat( "Helvetica", 20, 0xd4d4d4 );
}

Then, tell the theme that when the sub-component has your custom style, it should pass the component to your function:

getStyleProviderForClass( Header )
    .setFunctionForStyleName( "custom-panel-header", setCustomPanelHeaderStyles );