Learning Flex – Lesson 10, Creating Custom Components with ActionScript 3.0

Creating a custom component in ActionScript is very similar to how it’s done using MXML. First choose the class your new class will extend (if any) and add any properties or methods you require. If your component is a displayable container, you will probably want to override the methods createChildren() and updateDisplayList() to define the creation, sizing and positioning of any children.

In the same way you use @Embed to add images in MXML, you can add them to ActionScript using [Embed("path to image")] followed directly below by a variable of type Class which will hold a reference to it. Note that in this case, the path to the image is relative to the location of the component file.

Overriding createChildren()

This method is called automatically at initialization and is used to add child components to a container. The initialization sequence is:

  • the class constructor
  • createChildren()
  • commitProperties()
  • measure()
  • updateDisplayList()

The last four methods are defined in mx.core.UIObject.

The commitProperties() method is used to set properties based on other values that are already set or to explicitly pass in new properties to be set in newly created components. As it’s called after all the children are created, it’s guaranteed that they have been successfully initialized so any complex property work can proceed. This method is also called after invalidateProperties() is called so you can use that as a kind of “dirty” flag and then use commitProperties() to decide based on the change, if you need to do any complex processing to update particular values or not.

The measure() method is used to calculate the the height and width required for the child components.

Within the createChildren() method, we can add components by creating objects of the required class and then using this.addChild() or this.addChildAt() to add them to the component (although they are not displayed at this stage). Just using addChild() will add children in the order they are declared, addChildAt() allows you to specify a zero based index into the display list.

Chrome and Raw Children

Flex containers have two types of display area, the layout area where children are drawn and the chrome which is the border, background, scrollbars etc area. The base class flash.display.DisplayObjectContainer does not distinguish between the two. They are both accessible via getChildAt() and count as part of the numChildren property. The mx.core.Container class (which is the superclass for all Flex containers) overrides these elements, only showing the child components. To gain access to the chrome as well, you need to use the rawChildren property and the associated method, rawChildren.addChild()

Sizing and Positioning

Every component that does not have an explicit or relative size specified must be allocated a size before it can be displayed. Components must be able to provide a recommended size. The method that is used to do this is measure().

When the LayoutManager needs to determine the layout of the application, it asks all the components starting with the most deeply nested to provide an explicit or recommended size. Once this is done, it works from the Application container back down, assigning sizes and moving components into place on the screen.

If the recommended sizes add up to more space than is available, the LayoutManager informs the Application container of the usable width and height and it decides how much space to give it’s immediate children¬† and where they should be placed. Each of these in turn goes through the process for it’s children and so on down the line.

The method inside each component that is responsible for the sizing and positioning of it’s children is called updateDisplayList().

This process takes place each time the application re-sizes so it makes sense not to get too carried away with large numbers of containers.

The measure() method

Each implementation of measure() is different as each has different constraints in layout. All however must provide measuredHeight, measuredWidth, measuredMinHeight and measuredMinWidth.

The first two are the ideal size requested by this component when there’s enough room available. The min versions are the smallest size the component needs to display correctly. The flex layout containers will never size a component smaller than these values. A custom component is free to ignore these values if it overrides updateDisplayList().

The updateDisplayList() method

This method requires two arguments; unscaledWidth and unscaledHeight both of type Number.  To ensure that the custom container itself is correctly displayed, you should call the superclass version within your override method (super.updateDisplayList() ) with the same parameters. These parameters provide the exact pixel width and height available. The size of the child components can be set using their setActualSize() methods passing in a width and height and their position using the move() method with an x and y of type Number (0,0) being top left.