.

Custom UI's, Listeners and MXP's

This tutorial will lead you through the more advanced aspects of how to use Flash Components. If you are a beginner on the topic of creating components please read the "Creating Flash MX Components" by Jonathan Kaye tutorial first, as this tutorial will not handle the details of how to write a component from scratch.

First we will talk about the difference between Smartclips and Components and see how Components are a great improvement. Then we will focus on tricks and techniques that will come in handy while creating the more complex "script-only" components.

The following topics will be discussed:

a. Creating custom Listeners
b. Creating a custom Interface
c. Packaging a component for distribution

Components versus Smartclips

Components are the sequel to the SmartClips found in Flash 5. The objective of SmartClips was to make it possible to reuse existing "normal" MovieClips. Certain properties of the "normal'" MovieClip had to be made variable by deriving them from variables in an initialization method. This in contrast to 'hard-coding' or designing the properties as is normal. Using the defined variables Flash would then in real-time define the behavior and design of the clip through these properties. The SmartClip properties panel enabled the end-user to influence the values of these properties at design-time.



The main disadvantage of using SmartClips is that it is difficult to capture all of the different aspects of the MovieClip in variables. The result of this is that design and functionality are locked in the clip, making many SmartClips only semi-customizable to the users' demands.

Flash Components solve this problem. Although it is still possible to use the SmartClips method to make MovieClips reusable, there is now a better method: by using MX you can attach a component to any clip on your stage. This way design can be separated from functionality; this creates more generic components which ensure greater usability.



Flash Components can contain graphic content just like Smartclips. Using them in this manner is pretty simple in certain situations; many of the default Flash Components contain graphic content (FcheckBox, Fbutton, etc.). Components containing graphic content can be attached to another movie clip, however in this tutorial we focus on (to the user) invisible components which are to be attached to a "normal" clip on the stage.

Creating custom Listeners

More about Listeners in general

In this part of the tutorial you will learn how to set up a simple Listener system to add to your own Flash Components. Listeners provide a very convenient way of connecting different objects to each other, without the need of writing a great deal of code.

A Listener method enables an object to react to changes in the object it is listening to. Many predefined Flash objects already support Listeners. The Mouse object is a good example. Take a look at the following code (which would typically be placed in the root of your movie):
positionField.onMouseMove = function() {
this.text = _xmouse + ", " + _ymouse;
}

Mouse.addListener(positionField);
Let's break down this piece of Action Script to see what happens.

First, a function named 'onMouseMove' is added to an on-stage textfield named 'positionField'. This function handles one of the supported Listeners methods available for Mouse; in this case onMouseMove. Other Listener functions for Mouse are onMouseUp and onMouseDown, for more information on mouse Listeners check the online help in Flash MX.

The onMouseMove function is triggered every time the mouse is moved. In our simple implementation the textfield prints the mouse's current position every time the mouse is moved. This is executed by the line of code in which the .text property of the textfield is filled with a string containing the new mouse position.

The textfield starts receiving this event once it is added to the Listeners queue which is invoked by the last line of code. The object can be removed from the Listeners queue with the following statement:
Mouse.removeListener(positionField);
Adding Listeners to your own components

Although the previous example is quite simple and may not appear to be very useful, it demonstrates that Listeners have great potential. More so because, in contrast to the Object.watch method, they can be used to track getter/setter properties such as _x and _y.

As mentioned before, many of the predefined Flash objects are already equipped with an AddListener and removeListener method for Listener management. When creating your own components, it could be useful to support Listeners as well. In order to do so, you need to add a bit of code to the components you're creating.

The next step in this tutorial will teach you how to add such a system to your components. The system we use is very similar to Macromedia's own system, as it also uses an array to store references to the Listeners.

To get started download the example follow.zip, save its contents and open "follow.fla" in Flash MX (the other file, "followUI.fla" is dealt with in the 'Custom Interfaces' section of this article). Run the movie by clicking Control > Test Movie. You will now see a component, called Follow, in action. The Follow Component can simply be dropped from the library on a MovieClip (in this case the yellow circle) allowing this MovieClip to follow the mouse. The yellow circle chases the mouse and rotates towards it, the text field and the red circle are listening to the Follow Component Placed on the yellow circle.

Return to the .fla to find out how this works. Open the library panel and double click the Follow Component to edit it. In the component click the script layer to access the code. Let's go through the code step by step.

After creating the component an empty array to store the future Listeners in is added, this is done in the initialization routine:
FollowClass.prototype.init = function(){
// create empty Listeners list
this.listenersList = [];
...
more code
...
}
The next step is to create the methods that objects use to add themselves to the Listeners queue of a particular component. A method to remove Listeners from the queue is also created:
// method to add listener to queue
FollowClass.prototype.addListener = function(ref){
this.listenersList[ref] = ref;
}

// method to remove listener from queue
FollowClass.prototype.removeListener = function(ref){
delete this.listenersList[ref];
}
The listenersList array, declared during initialization, is used to store the Listener objects in the first function, which for obvious reasons is called addListener. The next function, removeListener, allows objects to remove themselves from the array.

Now we need a way to broadcast events to all listening objects. To do this the following function is created:
// send follow event to all Listeners
FollowClass.prototype.sendFollowEvent = function(rotation){
// walk through listeners list
for (var i in this.listenersList) {
// invoke onFollow handler in listener
this.listenersList[i].onFollow(rotation);
}
}
The sendFollowEvent function checks the list of listening objects and invokes their onFollow handler. When the onFollow handler is invoked, a value is also transmitted, in this case the rotation value of the target movie clip that the component controls.

The last step is to decide where the sendFollowEvent function should be placed in the code. It makes sense to trigger this function as soon as the value that is being transmitted changes. In this case, the rotation is constantly updated in the onEnterFrame function, therefore it is a good idea to place a call to sendFollowEvent in the onEnterFrame event:
FollowClass.prototype.onEnterFrame = function() {
if (this.enabled) {

// calculate rotation
...
more code
...

this.sendFollowEvent(degrees);
}
 
After the new position and rotation of the target movie clip have been calculated, the sendFollowEvent is called and the value of the local degrees variable is passed to it, enabling the sendFollowEvent function to broadcast that value to all Listeners.

That's all there's to it when it is kept simple. The system presented here could be extended with a routine to check if a Listener still exists and, if not, to remove it's entry from the Listeners array to keep the list up-to-date. Empty entries in the listeners list may occur when an object that was added is destroyed, without being removed from the listeners list first.

Another extension that could be made to the sendFollowEvent function is, for instance, an implementation in which it is possible to specify which handler should be invoked in the Listener objects, instead of always invoking the same handler (onFollow) like is being done in our example.

This concludes the discussion on how to customize component listeners. Next we discuss how to get a component's users to interact with the component through a custom interface.

Creating a Custom Interface

Flash Components support the use of custom interfaces. These replace the default settings window presented in the Property Inspector. A custom interface is simply a .swf that allows the user to set parameters.

Using custom interfaces with components has two advantages:

First of all, there's the obvious 'eye-candy' argument - a custom interface can look any way you want it to, because it is designed in Flash.

Another reason to use a custom interface is to provide the user of the component with a better tool to set the component's parameters. This is especially the case for complex components that have many or very specific parameters. For example, of the various methods the default Property Inspector offers for setting component variables, one method that is not present is a simple slider.

If you have not yet downloaded the follow.zip archive, do so now and extract the sample files "follow.fla" and "followUI.fla".
  • Open follow.fla in Flash MX.
  • Click the blue circle sitting on top of the yellow one.
  • A custom interface to set the properties of the Follow Component appears in the Property Inspector.
  • Drag the sliders to change the settings of the component and test the movie to see the new settings in effect.
The following section explains the XCH object which is at the heart of how custom interfaces work.

The XCH object

When you use a custom interface, the component on stage and the .swf loaded in the Property Inspector communicate with each other. This communication is done through an object called 'xch' (eXCHange object). Any change made to a variable stored in the 'xch' object is received and stored by the component it is linked to. It is not necessary to create this object yourself; Flash does it for you.

The XCH object enables the design of an interface for components and uses the 'xch' object to pass the settings made in the custom UI to the component. Creating a custom interface isn't very complicated, however, it is important to pay attention to the details.

Retrieving variables from the XCH object

First of all, you should make sure you have correctly set your components Custom UI property in the Component Definition dialog (accessible via the Library). In the case of the "follow.fla" example, the file "followUI.swf" is embedded in the .fla to serve as the custom interface for the Follow component. The interesting stuff happens inside the custom interface source file, "followUI.fla". Open this file in Flash MX and click the script layer in the root of the movie. You should see (amongst other things) the following in the Action Script editor:
_root.onEnterFrame = function() {
// adjust position of sliders to match components values:
speedSlider.setSlider(_root.xch.speed);
distanceSlider.setSlider(_root.xch.minDistance);
// set the contents of the textfield:
targetClip.text = (_root.xch._targetInstanceName);
// delete handler after setting sliders & textfield
delete _root.onEnterFrame;
}
In this piece of code, the speed and distance sliders are updated to reflect the values from the Follow component that was clicked on. This occurs when the root timeline of the movie enters its first frame, because the onEnterFrame has then been set.
_root.onEnterFrame = function()
Inside this function, the values of both sliders are set. It goes beyond the scope of this tutorial to fully explain how the Slider component works, what's important is the fact that the slider can be set to a certain value with the setSlider() method. Notice that the variables passed to the sliders via the setSlider() method both start with "_root.xch." (referring to the 'xch' object) and that they end with the variable names as they are defined in the Follow component definition dialog. The content of the textfield named "targetClip" is also set:
speedSlider.setSlider(_root.xch.speed);
distanceSlider.setSlider(_root.xch.minDistance);
targetClip.text = (_root.xch._targetInstanceName);
When the custom interface .swf is loaded, the variables declared in the Follow component definition dialog are added to the 'xch' object. To access these variables, all that needs to be done is to refer to them using the correct path, which is "_root.xch.variableName".

Because the sliders only need to be set once, the handler is removed afterwards:
delete _root.onEnterFrame;
Setting variables in the XCH object

At this point we have a way to retrieve values from the 'xch' object and we have a method to pass them through to our own interface elements. The interface is able to reflect the state of the component that is clicked on. The only thing that remains is to send the new values which are set in the interface (by dragging the sliders, for example) to the 'xch' object. This is also pretty straightforward. Take a look at the following code, which can be found in the root of "followUI.fla":
distanceMonitor.onSlide = function(value) {
// set the new distance value in the xch object
_root.xch.minDistance = value;
// update the distance shown in the text field
this.text = value + "pix";
}

distanceSlider.addListener(distanceMonitor);
In the first part of code, a method called "onSlide" is defined, which is added to a textfield named "distanceMonitor". Two things happen inside this method. First, the variable "_root.xch.minDistance" is set to a new value. Then, the content of the textfield is updated to reflect the new value so that the user can see it.

The last line of code adds the textfield to the Listener queue of the instance of the Slider component named "distanceSlider". Please refer to the Creating Custom Listeners section to find out more about Listeners and how they work. What's important to know for now, is that the "onSlide" method is called each time the distance slider is dragged.

When the "onSlide" method is invoked, it updates the "_root.xch.minDistance" variable to the new value. Repeat the steps above for the speed slider and you're done.

Using custom listeners and custom interfaces gives you powerful control over how a user interacts with your component. The last step is to distribute your component. Read on about this, our last subject.

Packaging a component for distribution

Once you've created a usable component you might want to distribute it, either to the Flash community or internally for your own or colleagues use. Flash 5 provided quite basic support for the distribution and management of SmartClips. You either had to store all your SmartClips in the same library or maintain your own system of .fla files to contain all SmartClips.

Flash MX greatly improves on above process through the new "Components Panel". This panel provides a clear view of all installed components. It enables you to drag and drop the component from the panel onto the stage. The contents of the "Components Panel" are defined when Flash is loaded, and is based upon the contents of the ConfigurationComponents directory in the Flash MX application data directory (this is located in different places dependent on your OS).

The directory contains at least one file: Flash UI Components.fla. This file contains default Flash components like Fbutton and FcheckBox. In order to show other components in the panel simply add the fla's that contain the Components you want to show, to above directory and restart Flash. In our case you would add the file "follow.fla" to the directory. When you have restarted Flash you should find an entry added to the list of components.

It's not much of an issue to find the correct folder on your own system and copy the correct files to this folder if you are the sole person using the components. However it's a different issue if you want to distribute your components to the rest of the Flash Community. It would mean that other developers would have to find the correct folder (and every OS has a different one) and copy the file. Some people might consider this to be a bit too much of a hassle.

However, Macromedia has solved this problem through the Exchange Manager. Open the Help menu in Flash and select the "Flash Exchange" entry. This will open your browser to the "Macromedia Exchange for Flash" site. Through this site Flash developers can exchange components and other Flash assets.

The resources you can download there are in the "MXP" format (and so are the components you can find on flashcomponents.net). These files have been created with the Macromedia Extension Manager, a program that can be downloaded for free from the Flash Exchange website.

Using the Extension Manager to distribute your components increases your audience and insures a hassle free installation of components. The user downloads the MXP file and installs it by double-clicking it. The Extension Manager automatically stores the component in the correct folder with the properties and options the author has assigned to it.

In short, the MXP format is the way to package you component for distribution. The format has loads of options - too many to list them here, so instead let's focus on packaging a simple component: the Follow component.

First of all the Extension Manager must de downloaded and installed. To package a component you either run Extension Manager stand-alone or you go to Flash -> Menu -> Help -> Manage Extensions. In the Extension Manager choose Menu -> File -> Package Extension. The Extension Manager now asks for a MXI file.

An MXI file is an XML file upon which the manager packages the component. Copy the following xml and save it as an MXI file. You can also download follow.zip which contains two example files: follow.mxi and follw.mxp. This is enough to create the package for the Follow component.

For a complete reference to the meaning of each tag, look for the "The Extension Installation File Format" reference. This file is available as PDF here.

The most important tag is the "files" tag.. The "files" tag is the where the location of the source files that should be put into the package are specified. The "files" tag can contain one or more "file" tags. One file tag specifies the location of one source file. The path to fill in at "source=" is relative to the folder the mxi is installed in. By specifying "$flash" at the start of the destination path the Extension Manager is told to install to the default Flash folder.

Take the above XML and save it to "Follow.MXI" in the same folder as "Follow.fla". Now create the MXP package by choosing the Package Extension from the File menu in the Extension Manager. Browse to the folder where you saved the MXI file and select it. The Extension Manager will now create you MXP package which you can then distribute.

In addition to packaging components the Extension Manager can also be used to package Flash Template Files and Custom Actionscript, which are then added to the reference and included in the color coding.

Conclusion

We are very enthusiastic about the possibilities Flash Components present and hope this tutorial has given you more insights into the fascinating world of Flash Components, enabling you to build better components which you can share easily with the rest of the community.




No comments found ! Click here to be the first adding comments for this tutorial!