This article is based on Flex4 in Action, published on 10-November-2010. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information.
You’ve used components since the start of this book. They range from controls like the simple Button that accept input from the user, to container components like the VBox. Custom components are “home-brewed” so to speak, and are created by extending the same base classes as the default components that are part of the Flex framework.
Now we’ll tell you about the underlying foundation of the Spark component architecture in Flex 4. Most importantly, you will learn key facets of that are specific to the Flex 4 Spark architecture. This will get you on your way toward building your own collection of Spark-based components that take advantage of Spark architecture.
Spark Component Architecture
If you’ve been a Flex developer for a little while now, or you’ve used a different framework for client side interface creation, you may have heard of the conceptual Model-View-Controller (MVC) architecture. The Flex 4 Spark component architecture puts a little spin on the MVC pattern, and adds a fourth part – the skin. This means that every Spark-based component has the following four pieces to it:
- Model: Properties and business logic are contained here, and are usually written in ActionScript. For the sake of best practice, you really should not be placing visual or behavioral logic along with the model. We will elaborate on that in a moment.
- View: Contains logic used mostly for the layout and positioning of the component on the stage during runtime. This information can be its own ActionScript class, but it is usually more logical to either: A) abstract the logic into a base class so it can be reused by other components, or B) add it to the component’s
- Controller: This is responsible for defining the behavior of the component, the states that are contained within it, and provides definitions of the sub-parts that are declared in the Skin class using variable names. This typically comes in the form of ActionScript.
- Skin: Declares all of the visual elements that make up the component. This is usually an MXML file (largely thanks to FXG), and is tightly coupled with the Controller.
There is currently a lot of debate on what we will explain next, and you will ultimately have to exercise best judgment using a combination of your logical reasoning skills, along with the knowledge that you are gaining in this article.
As you saw a moment ago, there are four pieces that make up the Spark component architecture. Where this gets confusing is that you will often only see two classes for these four parts, one in ActionScript and the other MXML. The ActionScript class typically wraps the model, view, and the controller pieces into a single class, while the MXML is strictly meant to act as the skin for the respective component. According to the Flex 4 documentation:
“The general rule is any code that is used by multiple skins belongs in the component class, and any code that is specific to a particular skin implementation lives in the skin.”
This makes sense in theory, but does not usually provide enough of what we often refer to as separation of concerns. This is why you might notice that the better Flex developers are using three layers for their components:
- Component: The controller and the view logic, often written in ActionScript
- Presentation Model: Contains the code for the model.
- Skin: The MXML skin file
With this method, it is reasonable to suggest that this takes things back to the core concept of the Model-View- Controller again; whereas the Component class is the controller, the presentation model class is the model, and the Skin becomes the view element of the MVC architecture.
Let’s put all this theory into practice by taking a look at some real-life situations.
The many flavors of custom components
Creating a custom component means extending a pre-existing class that either directly or indirectly extends one of the Flex framework classes. Picture three 2010 Ford Mustangs side-by-side. The first is the base Mustang Coupe with the standard V6 engine. The second is the Mustang GT with a 4.6-liter V8, upgraded wheels, and some other upgrades. The third is a Shelby Cobra, sporting 510-horsepower, and premium sound and navigation system among other upgrades. The second and third mustangs both extend the base mustang, so they inherit all of the properties of the first, and then add their own additional amenities.
Similarly, the Cobra extends the GT, so the Cobra inherits the properties of the GT and the standard Mustang, while adding its additional features. But wait! How could the Cobra and the GT inherit the properties of the standard Mustang if the engines are different? The answer is that the GT overrides the engine property of the standard Mustang, and the Cobra overrides the engine of the GT. The relationship between these three automobiles is illustrated in the simple class diagram shown in Figure 1.
When you extend classes in the Flex framework, you inherit the properties, functions, events, and styles from the class you are extending. This makes code a lot more manageable and is one of the fundamental characteristics of object oriented programming and code reusability. Let’s take a look at two different component types.
Simple vs. Composite
There are two major types of custom components: simple and composite. A simple custom component extends a single, pre-existing component.
The fun doesn’t stop there though. When developing Flex applications, you will find it valuable to group simple components together, keeping your application better organized. You can create components that group disparate components in what’s called a composite component, which is a container that holds any number of additional components inside of it.
MXML vs. ActionScript
When developing custom components, you have the option of creating your component in either MXML or ActionScript. In most cases, either one will do. The main advantage of MXML is that you can usually write the code needed with fewer lines. However, some flexibility is lost in regard to object customization, so advanced custom components are almost always written as ActionScript classes.
Creating your component in MXML is often a popular choice for composite components that are not very advanced in nature. An excellent example of this is a shipping information form. It is useful to have a reusable shipping form component because there are many applications that it can be used for. This means that if the component is created with loose coupling in mind, it can be a highly reusable composite component that can be built using MXML. This approach is the easiest to get started with.
1 2 3 4
MIGRATION TIP In Flex 3, MXML composite components were usually based on the Flex Canvas container from the Halo library. In Flex 4, MXML composite components are created using the MXMLComponent base class or the Group class from the Spark library.
Your second option is to create your component in ActionScript. This technique is more advanced because it requires stronger ActionScript skills. You can override the functions of the component class you’re extending from, and you have fine-grained control.
The advantage of this method is that you have far greater power to turn the coolness factor on your custom component into overdrive. The disadvantage is that if you are building a composite component, you can no longer lay out the controls in Flash Builder’s design view. Advanced developers consider this a small price to pay for the increased flexibility, while others feel that it slows down the development process. Finding the formula that works best for you is just a matter of trial-and-error.
Now that you have learned about the options available, the first custom component you will build is of the simple type.
1 2 3
TIP When it comes to making custom components, your goal should be to make it simple for other developers to use your component (even if it’s complicated inside). Later, we’ll give you tips on how to achieve this goal.
Creating simple custom components
At the most fundamental level, a viewable component (one which is added to the display list of your application) can be categorized according to the purpose served by the component. This includes: controls, containers, item renderers, effects, and skins.
The first custom component that you will build is an extension of the Flex ComboBox, and is considered a control because it is used to control application behavior by initiating an action or sequence of actions when the value is changed.
Build your own home-grown simple ComboBox
Let’s walk through a simple example. Say your application is geocentric, meaning that pieces of information tend to carry location data. As a result, a few forms require the user to specify an address of some sort. To help your users, you want to provide a drop-down menu of U.S. states, as figure 2 demonstrates.
Listing 1 CBStates.mxml: ComboBox-based custom component
1 2 3 4 5 6 7 8 9 10
<?xml version="1.0" encoding="utf-8"?> <mx:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo"> <mx:dataProvider> <mx:Object stateCode="AK" label="Alaska"/> <mx:Object stateCode="AL" label="Alabama"/> <!-- the rest of the US states --> </mx:dataProvider> </mx:ComboBox>
In code listing 1, you are presented with an example of simple custom ComboBox control that shows a listing of U.S. states when clicked, and allows selection of a state to be submitted as a data object. This type of component is highly reusable, since it is often needed when creating an address submission form. Listing 2 demonstrates how the component is instantiated with MXML in a Flex application.
Listing 2 Main application file for CBStates
1 2 3 4 5 6 7
<?xml version="1.0"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" backgroundColor="white" xmlns:local="*"> <local:CBStates/> </s:Application>
If you save the two files to the same directory and then run the application, you should end up with a drop-down combo box that lists all the U.S. states, as shown earlier in Figure 1.
One advantage of extending pre-existing Flex user interface components is that anyone who uses it will know its general properties and behaviors as a result of inheritance. In this case, if they know your simple custom component is based on a ComboBox, then they also know your component supports the same properties, events, styles, and functions as the Flex ComboBox control. Now you will take what you just learned and relate it to the Flex 4 Spark library and architecture.
Simple Spark Components
A visual object on the stage is considered a Spark component when it inherits the Spark component architecture by extending a Spark visual component base class. This includes:
- Any Spark library component (e.g. a Spark List)
If you are familiar with Flex 3, you may be wondering about the last item in the list, UIComponent. Technically, all visual components in Flex are subclasses of UIComponent, regardless of the component library that the component comes from. However, certain facets of a component that extends the base UIComponent class can make it a Spark component. For example, if an ActionScript composite component extends UIComponent as the base class, and then instantiates a Group or SkinnableContainer object to hold a set of display objects, then we would refer to it as a Spark composite component.
Most of the time, custom Spark-based components will extend the SkinnableComponent class, as you will see in the examples that will come later. But first, it’s time for some discussion on skins and how the SparkSkin object fits into the picture.
1 2 3 4 5 6 7 8 9 10
Migration Tip Beware! One of the biggest compatibility issues that haunted the Flex 4 beta releases involved placing Spark components inside of a Canvas container. The problem reared its ugly head in some unusual ways, even after it was thought to have been resolved. In one of my own experiences, the problem caused compile errors within Flash Builder beta of type "unknown" and source "unknown". The source of the problem turned out to be a SkinnableContainer that was instantiated inside of a Canvas. The moral of the story here is: if you find yourself debugging and feeling like you are chasing a ghost, consider checking your application to see if you have any Canvas objects before you start banging your head against the wall. If you do, try switching the Canvas to a Group. If that doesn't fix the problem, we still suggest leaving the Group in place of the Canvas as we have generally found the Group container to be more reliable and functional than Canvas.