Recipe 12.12 Creating a Component That Subclasses MovieClip
12.12.1 Problem
You want to create a
reusable
component, such as an interface widget, or even a component without a
UI.
12.12.2 Solution
Create a new movie clip symbol. On the first frame of the
symbol's timeline define the component class (which
must inherit from MovieClip). Then register the
class using Object.registerClass( ). All this
code should be encapsulated between #initclip and
#endinitclip pragmas.
12.12.3 Discussion
Components are a way of encapsulating movie clips so that the
instances can be easily configured by setting parameters through a
user interface at authoring time or through a programmatic interface
at runtime. For those who prefer to use Flash as a design tool, many
ready-made components (such as those included in the Flash UI
Component sets) can be dragged into a movie, and parameters can be
set via the Property inspector or Parameters panel. These components
add functionality to the movie without the designer having to write
all the code that is entailed. For our purposes, however, we will use
the term "component" more
specifically to refer to subclasses of
MovieClip. In other words, we will be discussing
components that are controlled programmatically instead of those that
are controlled via an author-time user interface.
There are five (or six) basic steps to creating a component:
Create a new movie clip symbol and give it a name in the Symbol
Property dialog box (accessed under Properties from the Library
panel's pop-up Options menu). As a best practice,
use the name you want to give to your component (such as
MyComponent). Export the movie clip symbol for ActionScript usage (using Linkage
from the Library panel's pop-up Options menu). As a
best practice, give the symbol a linkage identifier that follows the
naming convention of
ComponentNameSymbol
(such as MyComponentSymbol). Define the component class on the first frame of the component
timeline. The class should follow these guidelines: As a best practice, name the class
ComponentNameClass
(such as MyComponentClass). The class constructor should not take any parameters. The class must inherit from MovieClip by
assigning to the prototype property a new
MovieClip instance. (Subclassing the
MovieClip class is the only time you use a
MovieClip constructor in a
new statement.)
After defining the class, register it using
Object.registerClass( ). The first parameter
should be the symbol linkage identifier name specified as a string.
The second parameter should be a reference to the class. Place all the code for the component (the class definition and the
registration code) between #initclip and
#endinitclip pragmas so that the component class
is defined and registered before it is called. This is essential.
Without the #initclip pragma, the component class
is loaded only after instances of the component are loaded into the
movie. The sixth step in creating a component is to specify the component
definition for the symbol and optionally create a custom UI. You can
read more about this process in the Macromedia technote,
"Creating components in Macromedia Flash
MX" at http://www.macromedia.com/support/flash/applications/creating_comps.
For our purposes, we will consider this step optional. Technically, a
component is a component only if you have completed this step. But
this step only enables an author-time interface for configuring the
component instances—something we are not particularly
interested in from an ActionScript standpoint.
Using our working definition, components are the only way to
effectively subclass MovieClip, so they are the
only way to create custom object classes with a visual aspect. Basic
components can be created that do not subclass
MovieClip. These types of components allow users
to set values in the Component Parameters panel at authoring time but
not via ActionScript. Basic components cannot be instantiated with
ActionScript. In contrast, you can use ActionScript to control
MovieClip subclass components and can even
instantiate them using the attachMovie( )
method. Because a component class is registered to a particular
linkage identifier name, Flash automatically knows to call the
component class constructor function when a new instance of the
symbol is created using attachMovie( ).
Here is an example in which a component,
MyComponent, is created and used within a movie.
The component creates a text field within itself and has methods that
allow it to move about the screen to random spots at a set interval.
Create a new movie clip symbol named MyComponent. Open the Linkage properties for MyComponent
using the Library panel's pop-up Options menu.
Export the symbol for ActionScript and give it a linkage identifier
of MyComponentSymbol. On the first frame of the default layer of
MyComponent, add the following code: // Make sure everything is between the #initclip and #endinitclip pragmas.
#initclip
// The constructor function accepts no parameters.
function MyComponentClass ( ) {
// Create a text field that auto sizes. Set an initial text value.
this.createTextField("myTextField", 1, 0, 0, 0, 0);
this.myTextField.autoSize = true;
this.myTextField.text = "init text value";
}
// MyComponentClass subclasses MovieClip, as must all scriptable components.
MyComponentClass.prototype = new MovieClip( );
// Define a method that sets the text.
MyComponentClass.prototype.setText = function (val) {
this.myTextField.text = val;
};
// The beginMove( ) method uses setInterval( ) to call the move( ) method of the
// component at the specified rate. The interval reference is stored in a
// property so that it can be removed later.
MyComponentClass.prototype.beginMove = function (rate) {
this.moveInterval = setInterval(this, "move", rate);
};
// The endMove( ) method calls clearInterval( ) to stop the calls to move( ).
MyComponentClass.prototype.endMove = function ( ) {
clearInterval(this.moveInterval);
};
// The move( ) method is called automatically at an interval when beginMove( ) is
// called. This method sets the _x and _y properties of the component to random
// values within the Stage.
MyComponentClass.prototype.move = function ( ) {
this._x = Math.random( ) * 550;
this._y = Math.random( ) * 400;
};
// Register the component class to the linkage identifier for the symbol.
Object.registerClass("MyComponentSymbol", MyComponentClass);
#endinitclip Return to the first frame of the main timeline and add the following
code to create an instance of the component: // Create a new instance of the component. Because MyComponentClass is registered
// to the MyComponentSymbol linkage identifier, when this new instance is
// created, it will automatically call the MyComponentClass constructor.
_root.attachMovie("MyComponentSymbol", "myC", 1);
// Call the beginMove( ) method with a rate of 100. This causes the component to
// move approximately 10 times per second.
myC.beginMove(100);
// Define an interval callback function that calls the endMove( ) method for myC
// and clears the interval.
function doEndMove ( ) {
myC.endMove( );
clearInterval(cInterval);
}
// Set an interval at which doEndMove( ) is called after 10 seconds have elapsed.
cInterval = setInterval(doEndMove, 10000);
12.12.4 See Also
Chapters 14 and 16 of ActionScript for Flash MX: The
Definitive Guide cover movie clip subclasses and component
development in detail.
|