Accessing the component instance from a Flex skin
8th August 2008
Another little post about skinning Flex components…
If you need to access the component that a skin belongs to, you need to know that the skin’s parent is the component that you’re skinning. Which means you can access properties of the component through the skin’s parent (N.B. Don’t do this in the constructor – the skin isn’t added to the component’s display list until after the constructor has run).
For example, you can find a Button’s label as the label property of the button skin’s parent. Using this, you can create skins that vary based on the parent’s label. For example, a set of buttons for controlling video playback would all have different icons on them. Rather than creating different skins for each button, you can create one skin and draw a different icon based on the skin’s label (play, pause, etc).
Hiding a Button’s label
If, as above, you use a button’s label as an indicator for modifying a button skin, you may also want to hide the label graphic. The label graphic is the only child of the Buttonthat is a UITextField. And the Button is the skin’s parent. So, to hide the label you look through the parent’s children, find the UITextField, and set it’s visible property to false.
Example
Putting these two ideas together produces something like this
package
{
import mx.controls.Button;
import mx.core.UITextField;
import mx.skins.ProgrammaticSkin;
public class MediaButtonSkin extends ProgrammaticSkin
{
public function MediaButtonSkin()
{
super();
}
override protected function updateDisplayList(
w:Number, h:Number ):void
{
// check we're on a Button
if( ! parent ) return;
if( ! parent is Button )
throw( new Error( "MediaButtonSkin may only be
used on Button objects" ) );
super.updateDisplayList( w, h );
// find the label display UITextField and hide it
for( var i:int = 0; i < parent.numChildren; i++ )
{
if( parent.getChildAt( i ) is UITextField )
{
parent.getChildAt( i ).visible = false;
}
}
// choose a fill color based on the skin state
var fillColor:uint;
switch( name )
{
case "upSkin":
case "selectedUpSkin":
fillColor = 0xCC0000;
break;
case "overSkin":
case "selectedOverSkin":
fillColor = 0xFF3300;
break;
case "downSkin":
case "selectedDownSkin":
fillColor = 0xFF9900;
break;
case "disabledSkin":
case "selectedDisabledSkin":
fillColor = 0x7F0000;
break;
}
// set the circle properties
var radius:Number = Math.min( w, h ) / 2;
var centreX:Number = w / 2;
var centreY:Number = h / 2;
// draw the circle
graphics.clear();
graphics.beginFill( fillColor, 1 );
graphics.drawCircle( centreX, centreY, radius );
graphics.drawCircle( centreX, centreY, radius-3 );
graphics.endFill();
graphics.beginFill( fillColor, 0 );
graphics.drawCircle( centreX, centreY, radius-3 );
graphics.endFill();
// get the button's label text
var label:String = Button( parent ).label.toLowerCase();
// draw the graphics based on the label text
switch( label )
{
case "play":
var tipX:Number = centreX + radius * 0.5;
var backX:Number = centreX - radius * 0.3;
var tipYOffset:Number = radius * 0.45;
graphics.beginFill( fillColor, alpha );
graphics.moveTo( tipX, centreY );
graphics.lineTo( backX, centreY + tipYOffset );
graphics.lineTo( backX, centreY - tipYOffset );
graphics.lineTo( tipX, centreY );
graphics.endFill();
break;
case "pause":
var outX:Number = radius * 0.4;
var inX:Number = radius * 0.15;
var tipY:Number = radius * 0.45;
graphics.beginFill( fillColor, alpha );
graphics.drawRect( centreX + inX, centreY - tipY,
outX - inX, tipY * 2 );
graphics.drawRect( centreX - outX, centreY - tipY,
outX - inX, tipY * 2 );
graphics.endFill();
break;
}
}
}
}
Add this little bit of MXML
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="160" height="40" backgroundColor="0">
<mx:HBox x="45" y="5">
<mx:Button skin="MediaButtonSkin"
width="30" height="30" label="play"/>
<mx:Button skin="MediaButtonSkin"
width="30" height="30" label="pause"/>
</mx:HBox>
</mx:Application>
And the result looks like this
Flash required: You need version 9 or later of the free Flash player from Adobe to use this content. To download and install the free player from Adobe's web site click here.
Tags: Components, Flex, Skins

2 Comments add your own
Thanks! This was very helpful!
Erno | 8th August 2008 at 13:31
“Which means you can access properties of the component through the skin’s parent”
This is usually the case but isn’t guarenteed. It’s feasible that the skin could be inside another container, inside the component. Always worth bearing in mind.
Tink | 9th August 2008 at 23:54
Leave a Comment comment policy
XHTML: you can use these tags - <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>Subscribe to the comments via RSS Feed