About creating advanced Spark components

Simple visual components are subclasses of existing Flex components that modify the appearance of the component by using skins or styles, or add new functionality to the component. For example, you add a new event type to a Button control, or modify the default styles or skins of a DataGrid control. For more information, see Create simple visual components in ActionScript.

In advanced components, you typically perform the following actions:

  • Modify the basic functionality or logic of an existing component.

  • Create a composite component that encapsulates two or more components within it.

  • Create a skinnable component by creating a subclass of the SkinnableComponent class.

    A skinnable component uses two files: one for the component definition and one for the skin definition. Create a Spark skinnable component as a subclass of the SkinnableComponent class.

  • Create a nonskinnable component by creating a subclass of the UIComponent or other nonskinnable Spark class.

    A nonskinnable component is defined by a single file. Create a nonskinnable component as a subclass of the UIComponent class. You can also create one from a Spark class that does not have the SkinnableComponent class in its class hierarchy, such a Group or DataGroup.

This topic contains several examples of Spark ActionScript components. For more examples, examine the source code for the Spark components in your Flex installation directory. The spark.components and spark.components.supportClasses packages contain many of the Spark components mentioned in this topic.

Spark skinnable components and skin classes

When creating an skinnable Spark component in ActionScript, you create two classes: the component class and the skin class.

The component class defines the core behavior of the component. This behavior includes defining the events dispatched by the component, the data that the component represents, the skin parts implemented by the skin class, and the view states that the skin class supports.

The skin class manages the visual appearance of the component and creates visual subcomponents. The skin class defines the default layout of the component, its default size, the supported view states, graphics, and data representation.

About overriding protected UIComponent methods for Spark components

All Flex visual components are subclasses of the UIComponent class. Therefore, visual components inherit the methods, properties, events, styles, and effects defined by the UIComponent class.

To create an advanced visual component, you must implement a class constructor. Also, you optionally override one or more of the following protected methods of the UIComponent class:

UIComponent method

Description

commitProperties()

Commits any changes to component properties, either to make the changes occur at the same time or to ensure that properties are set in a specific order.

For more information, see Implementing the commitProperties() method for Spark components.

createChildren()

Creates any child components of the component. For example, the Halo ComboBox control contains a Halo TextInput control and a Halo Button control as child components.

Typically, you do not implement this method in a Spark component because any child components are defined in the skin class.

This topic does not describe how to implement the createChildren() method. For more information, see the example for creating a Halo component in Implementing the createChildren() method for MX components.

measure()

Sets the default size and default minimum size of the component.

You typically do not have to implement this method for Spark components. The default size of a Spark component is defined by the skin class, and by the children of the skin class. You also set the minimum and maximum sizes of the component in the root tag of the skin class.

This topic does not describe how to implement the measure() method. For more information, see the example for creating a MX components in Implementing the measure() method for MX components.

updateDisplayList()

Sizes and positions the children of the component on the screen based on all previous property and style settings, and draws any skins or graphic elements used by the component. The parent container for the component determines the size of the component itself.

Typically, you do not have to implement this method for Spark components. A few Spark components, such as spark.components.supportClasses.SkinnableComponent, do implement it. The SkinnableComponent class implements it to pass sizing information to the component's skin class.

This topic does not describe how to implement the updateDisplayList() method. For more information, see the example for creating a Halo component in Implementing the updateDisplayList() method for MX components.

Component users do not call these methods directly; Flex calls them as part of the initialization process of creating a component, or when other method calls occur. For more information, see About the component instantiation life cycle for MX components.

About overriding SkinnableComponent methods for Spark components

All Spark skinnable components are subclasses of the SkinnableComponent class. Therefore, skinnable components inherit the methods, properties, events, styles, and effects defined by the SkinnableComponent class.

To create an skinnable Spark component, you optionally override one or more of the following methods of the SkinnableComponent class:

SkinnableComponent method

Description

attachSkin()

detachSkin()

Called automatically by the commitProperties() method when a skin is added, attachSkin(), or a skin is removed, detachSkin(). You can optionally implement these methods to add a specific behavior to a skin.

Typically you do not implement these methods.

partAdded()

partRemoved()

Called automatically when a skin part is added or removed. You typically override partAdded() to attach event handlers to the skin part, configure the skin part, or perform other actions when a skin part is added. Implement the partRemoved() method to remove the even handlers added in partAdded().

For more information, see Implementing the partAdded() and partRemoved() methods for skinnable components for Spark components.

getCurrentSkinState()

Called automatically by the commitProperties() method to set the view state of the skin class.

For more information, see Implementing the getCurrentSkinState() method for skinnable components for Spark components.

Component users do not call these methods directly; Flex calls them as part of the initialization process of creating a component, or when other method calls occur. For more information, see About the component instantiation life cycle for MX components.

About the invalidation methods for Spark components

During the lifetime of a component, your application might modify the component by changing its size or position, modifying a property that controls its display, or modifying a style or skin property of the component. For example, you might change the font size of the text displayed in a component. As part of changing the font size, the component’s size might also change, which requires Flex to update the layout of the application. The layout operation might require Flex to invoke the commitProperties(), measure(), getCurrentSkinState(), and the updateDisplayList() methods of your component.

Your application can programmatically change the font size of a component much faster than Flex can update the layout of an application. Therefore, you only want to update the layout after you are sure that you’ve determined the final value of the font size.

In another scenario, when you set multiple properties of a component, such as the label and icon properties of a Button control, you want the commitProperties(), measure(), getCurrentSkinState(), and updateDisplayList() methods to execute only once, after all properties are set. You do not want these methods to execute when you set the label property, and then execute again when you set the icon property.

Also, several components might change their font size at the same time. Rather than updating the application layout after each component changes its font size, you want Flex to coordinate the layout operation to eliminate any redundant processing.

Flex uses an invalidation mechanism to synchronize modifications to components. Flex implements the invalidation mechanism as a set of methods that you call to signal that something about the component has changed and requires Flex to call the component’s commitProperties(), measure(), getCurrentSkinState(), or updateDisplayList() methods.

The following table describes the invalidation methods:

Invalidation method

Description

invalidateDisplayList()

Marks a component so that its updateDisplayList() method gets called during the next screen update.

invalidateProperties()

Marks a component so that its commitProperties() method gets called during the next screen update.

invalidateSize()

Marks a component so that its measure() method gets called during the next screen update.

invalidateSkinState()

Marks a component so that its commitProperties() method gets called on the next screen update to change the view state of the skin class. The commitProperties() method calls the getCurrentSkinState() method.

When a component calls an invalidation method, it signals to Flex that the component must be updated. When multiple components call invalidation methods, Flex coordinates updates so that they all occur together during the next screen update.

Typically, component users do not call the invalidation methods directly. Instead, they are called by the component’s setter methods, or by any other methods of a component class as necessary. For more information and examples, see Implementing the commitProperties() method for MX components.

About the Spark component instantiation life cycle

The component instantiation life cycle describes the sequence of steps that occur when you create a component object from a component class. As part of that life cycle, Flex automatically calls component methods, dispatches events, and makes the component visible.

The following example creates a Button control in ActionScript and adds it to a Group container:

// Create a Group container. 
var groupContainer:Group = new Group(); 
// Configure the Group container.  
groupContainer.x = 10; 
groupContainer.y = 10; 
 
// Create a Button control.  
var b:Button = new Button() 
// Configure the button control. 
b.label = "Submit"; 
... 
// Add the Button control to the Box container. 
groupContainer.addElement(b);

The following steps show what occurs when you execute the code to create the Button control, and add the control to the container:

  1. You call the component’s constructor, as the following code shows:

    // Create a Button control.  
    var b:Button = new Button()
  2. You configure the component by setting its properties, as the following code shows:

    // Configure the button control. 
    b.label = "Submit";

    Component setter methods might call the invalidateProperties(), invalidateSize(), invalidateSkinState(), or invalidateDisplayList() methods.

  3. You call the addElement() method to add the component to its parent, as the following code shows:

    // Add the Button control to the Box container. 
    gropContainer.addElement(b);

    Flex then performs the following actions:

  4. Sets the parent property for the component to reference its parent container.

  5. Computes the style settings for the component.

  6. Dispatches the preinitialize event on the component.

  7. Calls the component’s createChildren() method. For skinnable components, this causes a call to attachSkin(), which calls partAdded(), for all static parts defined in the skin file.

  8. Calls the invalidateProperties(), invalidateSize(), invalidateSkinSate(), and invalidateDisplayList() methods to trigger calls to the commitProperties(), measure(), getCurrentSkinState(), or updateDisplayList() methods during the next render event.

    The only exception to this rule is that Flex does not call the measure() method when the user sets the height and width of the component.

  9. Dispatches the initialize event on the component. At this time, all of the component’s children are initialized, but the component has not been sized or processed for layout. You can use this event to perform additional processing of the component before it is laid out.

    Because the initialize event is dispatched early in the component's startup sequence, make sure that none of your processing causes the component to invalidate itself. You typically perform any final processing during the creationComplete event.

  10. Dispatches the elementAdd event on the parent container.

  11. Dispatches the initialize event on the parent container.

  12. During the next render event, Flex performs the following actions:

    1. Calls the component’s commitProperties() method. For skinnable components, the commitProperties() method calls the getCurrentSkinState() methods.

    2. Calls the component’s measure() method.

    3. Calls the component’s updateDisplayList() method.

  13. Flex dispatches additional render events if the commitProperties(), measure(), or updateDisplayList() methods call the invalidateProperties(), invalidateSize(), invalidateSkinSate(), or invalidateDisplayList() methods.

  14. After the last render event occurs, Flex performs the following actions:

    1. Makes the component visible by setting the visible property to true.

    2. Dispatches the creationComplete event on the component. The component is sized and processed for layout. This event is only dispatched once when the component is created.

    3. Dispatches the updateComplete event on the component. Flex dispatches additional updateComplete events whenever the layout, position, size, or other visual characteristic of the component changes and the component is updated for display.

Most of the work for configuring a component occurs when you add the component to a container by using the addElement() method. That is because until you add the component to a container, Flex cannot determine its size, set inheriting style properties, or draw it on the screen.

You can also define your application in MXML, as the following example shows:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
    <s:Group> 
        <s:Button label="Submit"/> 
    </s:Group> 
</s:Application>

The sequence of steps that Flex executes when creating a component in MXML are equivalent to the steps described for ActionScript.

You can remove a component from a container by using the removeElement() method. If there are no references to the component, it is eventually deleted from memory by the garbage collection mechanism of Adobe® Flash® Player or Adobe® AIR™.

About the steps for creating a Spark component

When you implement a component, you override component methods, define new properties, dispatch new events, or perform any other customizations required by your application.

To implement your component, follow these general steps:

  1. Create the skin class for the component. You typically create the skin class in MXML. For more information on skins, see Spark Skinning.

  2. Create the component’s ActionScript class file.

    1. For a skinnable component, extend one of the base classes, such as SkinnableComponent, or a subclass of class SkinnableComponent. For a nonskinnable component, extend UIComponent or a Spark class that does not have SkinnableComponent in it class hierarchy.

    2. Implement the constructor.

    3. Implement the UIComponent.createChildren() method. You rarely have to implement this method for Spark components.

    4. Implement the UIComponent.commitProperties() method.

    5. Implement the UIComponent.measure() method. You rarely have to implement this method for Spark components.

    6. Implement the UIComponent.updateDisplayList() method. You rarely have to implement this method for Spark components.

    7. For a skinnable component, implement the SkinnableComponent.partAdded() and SkinnableComponent.partRemoved() methods.

    8. For a skinnable component, implement the SkinnableComponent.getCurrentSkinState() method.

    9. Add properties, methods, styles, events, and metadata.

  3. Deploy the component as an ActionScript file or as a SWC file.

For more information about MXML tag properties and embedding graphic and skin files, see Create simple visual components in ActionScript.

You do not have to override all component methods to define a new component. You only override the methods required to implement the functionality of your component. If you create a subclass of an existing component, such as Button, you implement only the methods necessary for you to add any new functionality to the component.

About interfaces

Flex uses interfaces to divide the basic functionality of components into discrete elements so that they can be implemented piece by piece. For example, to make your component focusable, it must implement the IFocusManagerComponent interface; to let it participate in the layout process, it must implement ILayoutClient interface.

To simplify the use of interfaces, the UIComponent class implements all of the interfaces defined in the following table, except for the IFocusManagerComponent interface. However, many subclasses of UIComponent implement the IFocusManagerComponent interface.

Therefore, if you create a subclass of the UIComponent class or subclass of UIComponent, such as SkinnableComponent, you do not have to implement these interfaces. But, if you create a component that is not a subclass of UIComponent, and you want to use that component in Flex, you might have to implement one or more of these interfaces.

The following table lists the main interfaces implemented by Flex components:

Interface

Use

IAdvancedStyleClient

Indicates that the component supports the advanced style subsystem.

IAutomationObject

Indicates that a component is an object within the automation object hierarchy.

IChildList

Indicates the number of children in a container.

IConstraintClient

Indicates that the component support layout constraints.

IDeferredInstantiationUIComponent

Indicates that a component or object can effect deferred instantiation.

IFlexDisplayObject

Specifies the interface for skin elements.

IFlexModule

indicates that the component can be used with module factories

IFocusManagerComponent

Indicates that a component or object is focusable, which means that the components can receive focus from the FocusManager. The UIComponent class does not implement IFocusable because some components are not intended to receive focus.

IInvalidating

Indicates that a component or object can use the invalidation mechanism to perform delayed, rather than immediate, property commitment, measurement, and drawing or layout.

ILayoutManagerClient

Indicates that a component or object can participate in the LayoutManager's commit, measure, and update sequence.

IPropertyChangeNotifier

Indicates that a component supports a specialized form of event propagation.

IStateClient

Indicates that the component supports view states.

IToolTipManagerClient

Indicates that a component has a toolTip property, and therefore is monitored by the ToolTipManager.

IUIComponent

Defines the basic set of APIs that you must implement in order to be a child of layout containers and lists.

IValidatorListener

Indicates that a component can listen for validation events, and therefore show a validation state, such as a red border and error tooltips.

IVisualElement

Indicates that the component can be laid out and displayed in a Spark application.