Creating Advanced Components
Trademarks 1 Step RoboPDF, ActiveEdit, ActiveTest, Authorware, Blue Sky Software, Blue Sky, Breeze, Breezo, Captivate, Central, ColdFusion, Contribute, Database Explorer, Director, Dreamweaver, Fireworks, Flash, FlashCast, FlashHelp, Flash Lite, FlashPaper, Flex, Flex Builder, Fontographer, FreeHand, Generator, HomeSite, JRun, MacRecorder, Macromedia, MXML, RoboEngine, RoboHelp, RoboInfo, RoboPDF, Roundtrip, Roundtrip HTML, Shockwave, SoundEdit, Studio MX, UltraDev, and WebHelp are either registered tradema
CONTENTS About creating components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Writing the component’s ActionScript code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Simple example of a class file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Selecting a parent class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 About the component instantiation life cycle . . . . . . .
Contents
Creating Advanced Components This article describes the details of creating advanced components for use in Macromedia Flex applications. The majority of the work is in writing the ActionScript class file, which derives from Flex existing classes, and adding your own custom functionality. For an additional article on creating Flex components, including examples, see www.macromedia.com/devnet/flex/articles/creating_comp.html. About creating components . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
e Implement the createChildren() method. f Implement the commitProperties() method. g Implement the measure() method. h Implement the layoutChildren() method. i Implement the draw() method. j Add properties, methods, styles, events, and other metadata. 3 Compile a SWC file using compc. The ordering of methods that you implement in this process mirrors that in the component instantiation life cycle.
Note: Macromedia recommends that you base your components on the UIComponent class rather than the UIObject class. The UIComponent class provides more built-in functionality, but maintains the flexibility of extending the UIObject class. UIObject and UIComponent are the base classes of the component architecture. Understanding the principles at work in these two classes is important for building components. The following table briefly describes the two base classes: Class Extends mx.core.
The UIComponent (mx.core.UIComponent) class is a subclass of the UIObject class. It defines high-level behaviors that are specific to a graphical object. The UIComponent class handles enduser interactions (such as clicking and focus) and component enabling and disabling. The UIComponent class inherits all the methods, properties, and events of the UIObject class. Note: UIComponent also handles dragging, but you should not override the startDrag() method when defining custom components.
Each class can contain only one constructor method; overloaded constructor methods are not supported in ActionScript 2.0. Implementing the init() method Flash calls the init() method when the class is created. At a minimum, the init() method should call the superclass’s init() method. The width and height of the component are not set until after this method is called. function init(Void):Void { super.init(); invalidate(); } Note: Do not create child objects in the init() method.
Application performance is better when you pass style properties in the initObject argument instead of calling the setStyle() method. The following example creates TextInput and SimpleButton components: function createChildren():Void { if (text_mc == undefined) createClassObject(TextInput, "text_mc", 0, { preferredWidth: 80, editable:false }); text_mc.addEventListener("change", this); text_mc.
You can set the following properties in the measure() method. Flex calculates the values of these properties, but you can override them in the measure() method: • • • • • • _measuredMinWidth _measuredMaxWidth _measuredMinHeight _measuredMaxHeight _measuredPreferredWidth _measuredPreferredHeight The properties define limits for when the object is resized. These measured properties are used for layout in containers if your component doesn’t explicitly set a preferredWidth or preferredHeight attribute.
Implementing the layoutChildren() method The layoutChildren() method positions subobjects within the confines set by the UIObject.layoutWidth and UIObject.layoutHeight properties of your component. Each component should implement this method. Use the layoutChildren() method rather than the size() method, which is used primarily by Macromedia Flash designers to perform the same function. Use the UIObject.width and UIObject.height properties of the child controls when changing the size of the children.
Inside the draw() method, you can use calls to the Flash drawing API, defined by the MovieClip class, to draw borders, rules, and other graphical elements. You can also call the clear() method, which removes the visible objects. In general, to set lengths in the draw() method, you should use this.layoutWidth and this.layoutHeight properties instead of width and height. For more information on the drawing API, see the MovieClip class in Flex ActionScript Language Reference.
To make your components reusable in MXML, you can set component properties using tag attributes. For example, you might want to allow the user to pass a value to your component, as the following example shows: To create components that take tag attributes in MXML, you define a variable with the same name in your class definition: class MyComponent extends UIComponent { var prop1:Number; ... } Flex automatically initializes prop1 based on the value set in the MXML tag.
You add these keywords anywhere inside the class definition. For more information on embedding assets, see Developing Flex Applications. To create a SWF file from which you embed assets, create a new FLA file and insert new symbols. For each symbol, select Export for ActionScript or place the symbols on the stage before saving the file as a SWF file. Handling events The event model is a dispatcher-listener model based on the DOM Level 3 proposal for event architectures.
For example, you define a component called ModalText as the following example shows: [Event("myEvent")] class ModalText extends UIComponent { ... } Within the body of your class definition, you then use the dispatchEvent() method to dispatch myEvent. You can then handle the event in MXML as the following example shows:
About invalidation Macromedia recommends that a component not update itself immediately in most cases, but instead save a copy of the new property value, set a flag indicating what changed, and call one of the invalidation methods. The following are the invalidation methods: invalidateSize() Indicates that one of the _measured properties have changed. This results in a call to the measure() method.
Making components accessible A growing requirement for web content is that it should be accessible to people who have disabilities. Visually impaired people can use the visual content in Flash applications by means of screen reader software, which provides an audio description of the material on the screen. When you create a component, you can include ActionScript that enables the component and a screen reader to communicate.
• Assume an initial state. Because style properties are on the object, you can set initial settings for • • • styles and properties so your initialization code does not have to set them when the object is constructed, unless the user overrides the default state. When defining the symbol, do not select the Export in First Frame option unless it is absolutely necessary.
[Embed(source="Modal2.swf", symbol="ModalOverSkin")] var modeOverSkinName:String; [Embed(source="Modal2.swf", symbol="ModalDownSkin")] var modeDownSkinName:String; // Note that we test for the existence of the children before creating them. // This is optional, but we do this so a subclass can create a different // child instead. function createChildren():Void { if (text_mc == undefined) createClassObject(TextInput, "text_mc", 0, { preferredWidth: 80, editable:false }); text_mc.
// Draw a simple border around everything. lineStyle(1,0x000000,100); drawRect(0, 0, width, height); } /*** h) Add methods, properties, and metadata. ***/ // The general pattern for properties is to specify a private // holder variable. private var __labelPlacement:String = "left"; // Create a getter/setter pair so you know when it changes. [ChangeEvent("placementChanged")] [Inspectable(defaultValue="left", enumeration="left, right")] function set labelPlacement(p:String) { // Store the new value.
You can also handle the textChanged event if you want to determine when the ModalText.text property is modified, as the following example shows: Note that to trigger the event, you have to modify the ModalText.text property directly; entering text into the TextInput control does not trigger the event.
One possible remedy is to add a static variable dependency to the class definition. Flex knows that all static variable dependencies must be ready before the class is initialized, so it orders the class loading correctly. The following example adds a static variable to tell the linker that class A must be initialized before class B: class mx.example.A { static function foo():Number { return 5; } } class mx.example.B { static function bar():Number { return mx.example.A.foo(); } static var z = B.
Creating Advanced Components