Override the LabelItemRenderer.layoutComponents() method in an item renderer

By default, the LabelItemRenderer class uses a single spark.components.supportClasses.StyleableTextField control to display a String. The name of the StyleableTextField control in the item renderer is labelDisplay.

In the next example, you define an item renderer to display multiple fields of a data item in separate StyleableTextField controls in the item renderer. This example uses the predefined labelDisplay control to display the first and last name fields of the data item. It then adds a second StyleableTextField control to display the company ID field.

Shown below is the view component for the mobile application:

<?xml version="1.0" encoding="utf-8"?>
<!-- containers\mobile\views\EmployeeMainViewIR.mxml -->
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    title="Employees View Main">
    <s:layout>
        <s:VerticalLayout paddingTop="10"/>
    </s:layout>

    <fx:Script>
        <![CDATA[
            public function myLabelFunction(item:Object):String {
                return item.lastName + ', ' + item.firstName;;
            }
        ]]>
    </fx:Script>
    
    <s:Label text="Select an employee name"/>
    <s:List id="myList"
        width="100%" height="100%"
        itemRenderer="myComponents.MyGroupItemRenderer"
        labelFunction="myLabelFunction">
        <s:ArrayCollection>
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/>
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/>
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/>
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/>
        </s:ArrayCollection>
    </s:List>
</s:View>
The List control uses the itemRenderer property to specify the name of the custom item renderer as MyGroupItemRenderer.as. In MyGroupItemRenderer.as, you:
  • Define the StyleableTextField control named compLabelDisplay.

  • Override the protected createChildren() method to create the compLabelDisplay control.

  • Override the protected styleChanged() method to propagate and style changes to the compLabelDisplay control.

  • Override the data property to initialize the compLabelDisplay control. The data property contains the original Object representing the data item in the List control.

  • Override the measure() method to calculate the size of the labelDsiplay and compLabelDisplay controls.

  • Override the layoutContents() method to size and position the labelDisplay and compLabelDisplay controls. The override uses the padding styles to calculate the availale space for the components.

Shown below is the definition of MyGroupItemRenderer, the item renderer:
package myComponents
{
    // containers\mobile\myComponents\MyGroupItemRenderer.as
    import spark.components.LabelItemRenderer;
    import spark.components.supportClasses.StyleableTextField;

    public class MyGroupItemRenderer extends LabelItemRenderer
    {
        public function MyGroupItemRenderer(){
            super();
        }
        
        // Define the StyleableTextField control used 
        // to display the company ID.
        public var compLabelDisplay:StyleableTextField;
        
        // The distance between the label and the company ID.
        public var verticalGap:Number = 10;
        
        // Override createChildren() to create the StyleableTextField control.
        override protected function createChildren():void {
            super.createChildren();
            
            // Make sure it does not already exist.
            if (!compLabelDisplay) {
                compLabelDisplay = new StyleableTextField();
                
                // Specify The object that provides styles for the control. 
                // This property must be set for the control to pick up 
                // the correct styles. 
                compLabelDisplay.styleName = this;
                
                // Set basic attributes of the control.
                compLabelDisplay.editable = false;
                compLabelDisplay.selectable = false;
                compLabelDisplay.multiline = false;
                compLabelDisplay.wordWrap = false;
                
                // Add the control as a child of the item renderer.
                addChild(compLabelDisplay);
            }
        }
        
        // Override styleChanged() to proopgate style changes to compLabelDisplay.
        override public function styleChanged(styleName:String):void {
            super.styleChanged(styleName);
            
            // Pass any style changes to compLabelDisplay. 
            if (compLabelDisplay)
                compLabelDisplay.styleChanged(styleName);
        }
        
        // Override the data property to initialize compLabelDisplay.
        // The label function in the view specifies the String 
        // displayed in labelDisplay.
        override public function set data(value:Object):void {
            super.data = value;
            
            compLabelDisplay.text = String(value.companyID);
        }
        
        // Override measure() to calculate the size required by the item renderer.
        override protected function measure():void {
            // Measure the labelDisplay by calling super.measure()
            super.measure();

            // Then consider the compLabelDisplay if it exists.
            if (compLabelDisplay)
            {
                var horizontalPadding:Number = getStyle("paddingLeft") + getStyle("paddingRight");
                var verticalPadding:Number = getStyle("paddingTop") + getStyle("paddingBottom");
                
                // Commit the styles changes to compLabelDisplay. 
                // This method must be called before the text is displayed, 
                // and any time the styles have changed. 
                // This method does nothing if the styles have already been committed. 
                compLabelDisplay.commitStyles();
                measuredWidth =  Math.max(getElementPreferredWidth(labelDisplay), getElementPreferredWidth(compLabelDisplay))
                measuredWidth += horizontalPadding;
                
                measuredHeight =  getElementPreferredHeight(labelDisplay);
                measuredHeight += getElementPreferredHeight(compLabelDisplay);
                measuredHeight += verticalPadding + verticalGap;
            }
        }
        
        // Override layoutContents() to lay out the item renderer.
        override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void {
            // Because you are handling the layout of both the 
            // predefined labelDisplay component and the new 
            // compLabelDisplay component, you do not have to call
            // super.layoutContents().
            
            // Make sure labelDisplay and compLabelDisplay exist.
            if (!labelDisplay)
                return;
            if (!compLabelDisplay)
                return;
            
            // Get the padding from the associated styles.
            var paddingLeft:Number = getStyle("paddingLeft"); 
            var paddingRight:Number = getStyle("paddingRight");
            var paddingTop:Number = getStyle("paddingTop");
            var paddingBottom:Number = getStyle("paddingBottom");
            
            // Calculate the available space for the component.
            var viewWidth:Number  = unscaledWidth - paddingLeft - paddingRight;
            var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom;
            
            // Calcualte the size of the labelDisplay component.
            var labelWidth:Number = Math.max(viewWidth, 0); 
            var labelHeight:Number = 0;
            
            if (label != "") {
                labelDisplay.commitStyles();
                
                // Reset text if it was truncated before.
                if (labelDisplay.isTruncated)
                    labelDisplay.text = label;
                
                labelHeight = getElementPreferredHeight(labelDisplay);
            }
            
            // Set the size and position of the labelDisplay component. 
            setElementSize(labelDisplay, labelWidth, labelHeight);    
            setElementPosition(labelDisplay, paddingLeft, paddingTop);
            
            // Attempt to truncate the text now that we have its official width
            labelDisplay.truncateToFit();
            
            // Size and position the compLabelDisplay component.
            var compLabelWidth:Number = Math.max(viewWidth, 0);
            var compLabelHeight:Number = 0;
            
            compLabelDisplay.commitStyles();
            compLabelHeight = getElementPreferredHeight(compLabelDisplay);
            
            setElementSize(compLabelDisplay, compLabelWidth, compLabelHeight);
            setElementPosition(compLabelDisplay, paddingLeft, paddingTop + labelHeight + verticalGap);
        }
    }
}