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.

Advertisements

Learning Flex – Lesson 5, Part II

Building Custom ActionScript Classes

Building an application in MXML results in an ActionScript class. The MXML is converted to ActionScript, combined with any code within a Script tag and the resulting class is compiled into a swf. When you compile test.mxml, a file named test-generated.as is created with the line

public class Test extends mx.core.Application

If you want to see the generated as files, add -keep-generated-actionscript to the flex compiler arguments. In FlashDevelop, you can do this by selecting project,properties… and clicking the compiler options tab. Click on the + next to the Additional Compiler Options and enter the value in the column to the right of [0].

Value or Data Transfer Objects

This kind of object is implemented as an ActionScript class and can be considered a container for data. They are often used for transfer of information to the back end of an application (potentially a database).

Each class is defined within a package similarly to Java. In fact, ActionScript classes look very similar to Java classes. One of the differences is how variables are declared ( var variableName:type; rather than Type variableName; ).

The [Bindable] metadata tag specified before a class name means that all public properties in the class can be bound to controls or other data structures. This can be placed before individual properties to limit it’s scope.

Externalizing Model Data

You can read the data for a model from an XML file by specifying the source property as the location of the file. The data will then be automatically parsed into an ActionScript compatible data structure. Data retrieved from a model tag is untyped so non strings must be cast to their type before use.

Debugging with Trace Statements

Flex has a global method called trace() that allows you to output data to the console when running the debugger version of the Flash player. It takes a string as the value and outputs the current value to the console. Defining a toString():String function within a custom class allows trace statements to automatically call this function if an object of that class is provided in a trace statement.