Adding Styling Support

One of the key features of Flex that Flash Player does not inherently support is styles. As we discussed earlier in the book, styles in Flex are a robust mechanism for defining component styles on an instance, class, or global basis, within MXML, ActionScript, and CSS. Styling support is built into the Flex framework and is exposed to custom components that inherit from UIComponent. Because of this, the complexity for integrating styling support for our components is greatly reduced.

To add support for styles, you need to add a style metadata tag and override the styleChanged() method. After you do that, you can use the getStyle() utility method from within your component to retrieve the value of the style. In this section, we will build the code to add a horizontalGap style that will control the space between the icon and the label in our instant messenger status icon component.

First, you need to define the style metadata tag by preceding the class declaration, specifying the style’s name and type, and usually disable inheritance:

[Style(name="horizontalGap",type="int", inheriting="false")]
public class StatusIcon extends UIComponent
{

Next, you need to implement the styleChanged() method:

override public  function styleChanged(styleProp:String):void
{
    super.styleChanged(styleProp);
    if(styleProp == "horizontalGap")
    {
        invalidateSize();
        invalidateDisplayList();
    }
}

In styleChanged(), we first call super.styleChanged(), passing it the styleProp value. Then we check for the changed value. Because styleChanged() is called whenever a style is changed, you need to check what style has changed and handle each type of style change separately. If you do not conditionally check for this you will likely run into performance issues, as the framework calls styleChanged() at different times throughout the application life cycle.

In the implementation of styleChanged(), after you check for the properly styled property, you call the invalidate methods. Although you could handle the required style changes with styleChanged(), typically it is best to call the proper invalidation methods and have the component redraw what it needs to. In this case, the component needs to recalculate its size and perform the drawing and layout functions.

With basic implementation of styling added to the StatusIcon, now we can update the rest of the component to support the new style. The simplest way to retrieve the style value from within our validation methods is to call the getStyle() function. The getStyle() function retrieves the value of a particular style. For example, it will automatically handle instance- versus class-based style values for you. However, if getStyle() cannot find a value for a style you request, it will return undefined. You should make sure that you handle such cases by providing a default value of your own if none exists. A common way to do this is to define a private getter function for the style. In our example, the getter should be called horizontalGapDefault. Here is the getter function that attempts to retrieve a valid value from getStyle(). If it does not find a valid value, it will return a default value of 5.

private function get horizontalGapDefault():int
{
    var horizontalGap:Number = getStyle("horizontalGap");
    return  (horizontalGap == undefined ? 5 : horizontalGap);
}

Now that we have a convenient method of retrieving the style, let’s update the validation methods to support the new style:

override protected function measure():void
{
    super.measure();
    measuredHeight = measuredMinHeight = currentIcon.height;
    measuredWidth = measuredMinWidth = currentIcon.width+horizontalGapDefault
+displayNameLabel.getExplicitOrMeasuredWidth
();
}

override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
    super.updateDisplayList(unscaledWidth,unscaledHeight);
    displayNameLabel.move(currentIcon.x + currentIcon.width +
horizontalGapDefault,0);
    displayNameLabel.setActualSize(unscaledWidth-currentIcon.width -
horizontalGapDefault,unscaledHeight);
}

When child components exist that contain their own styles, you will often want to allow the child styles to be set as well. For example, it would be convenient if our status icon component supported styling of the label component’s font type and font size. There are two methods you can use to achieve this. You can have the label component inherit the same style values from its parent, or you can define a custom style that only that child will use.

To allow children to inherit directly from their parents, you only need to add a metadata tag, like so:

[Style(name="fontSize", type="Number", format="Length", inherit="yes")]

This method is very useful when a component does not contain many types of children. In the status icon component, this method works well because only one component uses the fontSize value. If there were many children, you might run into a situation where you want some children to have different styles than others. For such a case, you can define a custom style for a child. For our status icon component, the name of the style would be labelFontSize. The naming convention is to prefix the style with the component type. To add support for this style, you will first need to define the style metadata tags in the same way you did the other methods:

[Style(name="labelFontSize", type="Number", format="Length", inherit="no")]

Next, you need to manually handle this new style and set the style of the child. Here is the updated code:

private var labelFontSizeChanged:Boolean = false;

override protected function commitProperties():void
{
        //code omitted for brevity

        if(labelFontSizeChanged)
        {
            displayNameLabel.setStyle("fontSize",labelFontSizeDefault);
            labelFontSizeChanged = false;
        }
    }
}

private function get labelFontSizeDefault():Number
{
    return (getStyle("labelFontSize") == undefined ? 12 :
getStyle("labelFontSize"));
}

override public  function styleChanged(styleProp:String):void
{
    super.styleChanged(styleProp);
    if(styleProp == "horizontalGap")
    {
        invalidateSize();
        invalidateDisplayList();
    }

    if(styleProp=="labelFontSize")
    {
        labelFontSizeChanged = true;
        invalidateProperties();
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset