The classes serve as the basis for Flex's visual and non-visual components:
Visual component classes:
- Containers for layout (HBox, VBox, Canvas, Panel) and navigation (Accordion, Tab Navigator, ViewStack)
- Controls for data input (TextInput, TextArea, DateField, CheckBox, etc) and data presentation (List, DataGrid, Tree, etc)
- Controls for user interaction (Button, LinkBar, etc)
- Components for charting (BubbleChart, LineChart, PieChart, etc)
- Components for data access (HTTPService, WebService, RemoteObject, etc)
- Components for data collection (ArrayCollection, XMLListCollection)
- Components for data validation (EmailValidator, NumberValidator, RegExpValidator, etc) and data formatting (DateFormatter, PhoneFormatter, etc)
- Components for animation effects and state transitions (Move, Resize, Fade, etc)
- Skin and Style classes (Border, ProgrammaticSkin, CSSStyleDeclaration)
- Manager classes (BrowserManager, HistoryManager, CursorManager, LayoutManager, etc)
- Utility classes (ArrayUtil, ColorUtil, GraphicsUtil, etc)
- Language feature support classes (BindingUtils, ChangeWatcher, etc)
Note: Some of these classes are created for you at application start up (i.e. Manager classes) or do not require instantiation for use (i.e. Utility classes).The following example demonstrates utilization of a built-in Button component by way of a public property (label) and style (color) while registering a handler on the buttonDown event (aka event listener).
90% of your Flex development will require built-in components. The rest will require custom components.
Note: The remainder of this entry will focus on visual components. Visual components eligible for participation in the Flex Framework descend from the UIComponent class which descends from the DisplayObject class. The DisplayObject class is the base class for all objects that can be placed on the display list.A custom visual component is required in the following scenarios:
- You want to customize the functionality of a built-in visual component to meet your specific requirements
- Nothing in the Flex Class Library comes close to the functionality you want so you need to build a custom visual component from scratch
- You want to package multiple components into one custom visual component for the sake of modularity and/or reusability
Scenario #1: You want to customize the functionality of a built-in visual component to meet your specific requirementsIn many instances, built-in components satisfy most of your needs. For example, you may need a control to render data as a vertical list while capturing the value of an HSlider's value property. The HSlider's value property will help determine the font color of each item in the vertical list.
Note: This custom component was built in a previous blog entry entitled Flex Examples - Item Renderers in Practice to demonstrate a technique used to facilitate real-time communication between a list-based control's item renderer and an external component.Extending the capabilities of a built-in component
Since Flex already provides a control capable of rendering data as a vertical list - List, we'll start with that and extend the functionality to include our new property. This can be done in MXML or ActionScript.
Note: Extending an existing class for the purpose of customization follows a fundamental object-oriented design principle - The Open-Closed Principle. This principle says that classes should be open for extension, but closed for modification.First, navigate to the desired package (directory) in Flex Builder where you'd like your custom component to reside.
If using MXML...
From the context menu (right-click), select File > New MXML Component. Set the 'Based on' field to 'List' and give your MXML component a name starting with a capital letter (to distinguish classes from objects, classes start with a capital letter whereas objects (instances of a class) do not).
The content of your new MXML component is as follows:
We're using a List as our base class (so List is our root tag), and we're going to extend its capabilities by adding any properties and methods we see fit. Here we will add a new property to the List control exposed publicly through a getter and setter.
If using ActionScript...
Again, from the context menu select File > New ActionScript Class. Set the 'Superclass' field to mx.controls.List (or hit browse and type in List) and give your ActionScript class a name starting with a capital letter. Flex Builder will create your class with the following contents:
List is the base class we'd like to extend. Our new class (MyList) inherits the capabilities of a basic List control by extending it while providing an opportunity to customize the properties and methods to meet our needs.
Now we can create an instance of our new, customized list and utilize our new property.
Or, we can use it as we intended based on our previous requirements.
Overriding the behavior of a built-in component
In addition to extending the capabilities of a built-in component, we can change the way it currently behaves.
For example, a Label component is a perfect candidate for an Item Renderer. However, we may want to change the Label's text color when our Label is used as an Item Renderer and certain conditions apply.
Looking closely at the Label class' source file (ctrl-click a Label tag in Flex Builder) and knowing a thing or two about Item Renderers, we settle on the set data method. This method passes the data for an item to the Item Renderer.
Note: The Label class is eligible for item rendering based on the implementation of the IDataRenderer interface which enforces implementation of a data property getter and setter method. Without these methods, there would be no way to pass an item's data to the Label instance.We would like to add some additional logic to the set method to meet our requirements, therefore, we will extend the Label class and override this existing method.
Note: In most cases, it is critical that we preserve the base class' implementation of the method we wish to override. Therefore, in this example, we need to call super.data.9 times out of 10, you can enhance a built-in component by extending or modifying its capabilities to fit your needs. Extend an existing class, add a new property or method, override an existing method, or even add new styles, effects or events....
Scenario #2: Nothing in the Flex Class Library comes close to the functionality you want so you need to build a custom visual component from scratchOn occasion, you may have the need to create a component from scratch. This approach is warranted when nothing is gained by extending the functionality of an existing, built-in component (container or control).
For example, you may choose to extend a VBox when you wish to "contain" child components while inheriting the built-in top-to-bottom layout capabilities. However, if layout for your component is dynamic and determined by a style setting, the layout rules of a VBox may not always apply.
As mentioned previously, all visual components eligible for participation in the Flex Framework descend from the UIComponent class. The UIComponent class implements 5 methods required of a visual component. These methods are known as the component lifecycle methods and they include:
Each method plays a particular role and makes a component unique to itself. For components added to the display list, these methods are called by the Flex Framework on application startup and may be called during the lifetime of a component as needed.
Implementation of the createChildren method is required if the visual component is a composite component. Composite components contain child objects. The createChildren method is only called once when the component is added to the display list.
By coordinating property changes and ensuring expensive calculations are not performed unnecessarily, the commitProperties method can help developers achieve optimal application performance.
The logic required to determine the custom component's default size and, optionally, default minimum size is contained within the measure method.
Container components utilize the layoutChrome method to define border area.
The sizing and positioning of child components is calculated within the updateDisplayList method.
For more information, Adobe has provided a more detailed description of each component lifecycle method.
The following example demonstrates the use of a custom visual component. This component consists of 2 child objects - a TextArea and a Button. The TextArea can be enabled/disabled programatically or by clicking the button. The layout can also be changed at runtime using the radio buttons.
View source is also enabled to provide insight into the structure of the custom component.
Scenario #3: You want to package multiple components into one custom visual component for the sake of modularity and/or reusabilityRather than creating an application consisting of one monolithic file, it is common practice to break an application down into pieces. This technique promotes code reuse and better organization.
Creating custom components to encapsulate distinct application views
Most Flex applications contain multiple views. A view consists of the components required to satisfy a particular task or objective. Each view could be constructed quite easily in the main application file. For example, the following application consist of 2 views - a Login View and a Search View.
However, as the application inevitably grows, so does the amount of code in the main application file. Before you know it, it is hard to tell where one view ends and another one begins.
To prevent duplicate code and unwieldy file sizes, consider breaking your application into pieces designed to perform a singular task (for example, "login" is a task represented by a unique view and warrants its own component). This is done by creating custom components like we did before.
This becomes essential as your views become more complex (i.e. more internal (child) components, view states, events, etc).
Note: Because our Login view was packaged into a LoginView component, access to the application's login method was no longer available. Communication between components should always be accomplished using events, therefore, the LoginView component now dispatches an event. A listener is created in the main application file to handle the event.
In this example, we've created two custom components (LoginView and SearchView) for the purpose of packaging multiple components together. We didn't reduce the amout of code but we did reduce clutter, and if we want, we can reuse these components without copying/pasting code.
Whether you're looking to extend the capabilities of an existing component, create a component from scratch or group components into views, Flex provides the mechanism to do so. Have fun!