Give us a call 203-379-0773
Check out our Angular Book Series.

Implementing States in a Mobile Skin or Mobile ItemRenderer.

In the most recent Flextras Friday Lunch episode, I spoke a little about how states have been implemented in various version of the Flex SDK. I assume most of the readers here are familiar with the Flex 3 State classes and the new MXML syntax introduced in Flex 4. This blog post is going to focus on the tail end of my presentation, which is how to implement states in Mobile Skins-or Mobile ItemRenderers.

States In Mobile Skins don't exist

Perhaps the best way to say it is that states in Mobile Skins don't exist. They don't exist in the same way that they existed in Flex 3. In Flex 3, we had an explicit state class which had an array of different overrides to change styles or properties. The overrides could add or remove children. Unfortunately they were complicated and tedious to implement. The Flex 4 MXML State syntax greatly simplified the implementation of states, although I'm unclear what was going on under the hood.

When building Mobile Skins, we should be building skins in 100% ActionScript. We do not have the benefit of the MXML Syntax. That begs to question, how do we implement states in a mobile skin? The answer is:

Manually

Instead of relying on the Flex Compiler to do our magic, or a State object with a set of overrides, we have to manually code our state changes. If properties need changes, we change them. If components need to be removed, we remove them with removeChild(). If components need to be added we do so with addChild(). It is a very manual process.

Implementing the States in the Component Class

Remember that a MobileSkin extends UIComponent, and inherits many properties and methods from it. One of those properties is the currentState property.

Whenever the skin state changes in the component class, the currentState value is set on the skin class. The currentState set method will call a method named commitCurrentState(). It is in the commitCurrentState method you'll want to initiate state changes.

How you implement state changes depends on what the state change is. Most likely you'll invalidate size, properties, or displayList and perform changes in the relevant lifecycle method.

Changing The Background with States

I'm going to dissect the sample I created for most recent the Flextras Friday Lunch episode. This sample has two states, each with a different background. When the state changes, so does the background. The component class in this case is our main application file. It defines two states:

<s:states>
<s:State name="black" />
<s:State name="blue" />
</s:states>

These states could also have been defined in as metadata, and that is the more commonly used approach in an ActionScript only component class. The component has button that changes the states. The button handler toggles the value of a nextState string variable:

public var nextState : String;
protected function button1_clickHandler(event:MouseEvent):void
{
if(this.nextState == 'black'){
this.nextState = 'blue'
} else {
this.nextState = 'black'
}                
this.invalidateSkinState();
}

The button handler also invalidates the SkinState. This relates to the Spark Component LifeCycle. invalidateSkinState() will force commitProperites() to run during the next render event, which will in turn force getCurrentSkinState() to run. This is the getCurrentSkinState() method:

override protected function getCurrentSkinState():String
{
var result : String = '';
if(this.nextState == 'black'){
result = 'blue';
} else {
result = 'black'
}
return result;
}

The getCurrentSkinState() method is used to determine what the state of the skin does. commitProperties() calls this method if the skin state needs to be changed. Somewhere under the hood-most likely in SkinnableComponent's commitProperties() method-the skin's currentState is set to the value that this method returns.

Then the skin class takes over.

Implementing States in the Skin Class

In the component class, the skin state was invalidated, and therefore recalculated, and the currentState value is set on the skin class. currentState is implemented as a get/set method, and the set method will call the commitCurrentState() method. This is where the code in our skin class takes over:

protected var nextColor : int = 0x000000;
override protected function commitCurrentState():void{
super.commitCurrentState();
            
if(this.currentState == 'black'){
this.nextColor = 0x000000;
} else {
this.nextColor = 0x0000FF;
}            
this.invalidateDisplayList();
}

The implementation of this method is not much different than the button handler of the component class which was used to change the skin. It changes the nextColor property based on the value of the currentState. It also calls invalidateDisplayList().

The invalidateDisplayList() method will force updateDisplayList() to rerun during the next render event. updateDisplayList () will in turn call drawBackground(). In a MobileSkin you'll use the drawBackground method to-see if you can guess-draw the background.

override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void{
super.drawBackground(unscaledWidth, unscaledHeight);
        
this.graphics.clear();
this.graphics.beginFill(nextColor);
this.graphics.drawRect(0,0,unscaledWidth,unscaledHeight );
this.graphics.endFill();
}

In a mobile skin we want to avoid using MXML graphics for performance purposes. Most of the default MXML skins use MXML Graphics. In this case, we are using the Flash Graphics API to draw a background rectangle that makes up our background.

See the Running Sample

That's all there is to it. The complexity, or simplicity, of what you want to do depends largely on what you want to do. Some things are harder in ACtionScript than in MXML. Unfortunately for those of us trying to eek all the performance we can out of a mobile pp, States is one of those things we need to implement the long way.

Be sure to check out thesample, and the source code.

More advanced sample are available as part of the Flextras Mobile Component set; so if you're doing Mobile Development be sure to check out our free developer editions.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)