Adobe is changing the world through digital experiences. Our creative, marketing and document solutions empower everyone — from emerging artists to global brands — to bring digital creations to life and deliver them to the right person
at the right moment for the best results.

Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change.Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.

Prerequisite knowledge

User level

Required products

Sample files

In many SWF applications, developers need a way to programmatically monitor a timeline as it is played back so the code can take some action when a frame label or the end of the timeline is reached. Techniques for achieving this, however, have often conflicted with the design goal of separating timelines from actions.

In the past decade Adobe Flash has grown from a simple animation tool into a comprehensive authoring environment for creating rich content. Nowadays many rich media agencies have implemented a workflow where multiple people in different roles—including Flash designers and developers—can simultaneously work together on one project, and projects are split into many different FLA and ActionScript files that all fit a specific framework or conceptual structure.

As a result, it has become a key best practice to use FLA files primarily as a collection of multimedia elements and timeline animations, and to embody all logic in external ActionScript files. To enable this workflow, Flash CS3 Professional introduced the Document class as a default mechanism to link a FLA file to external ActionScript code.

Overall it has become pretty easy to separate timelines from actions or code. However, there is unfortunately one exception to the rule.

Consider the following scenario: A developer would like to run a piece of code after a certain timeline has played to a specific point, which is marked with a label. How does he know exactly when this point has been reached? To solve this problem, the developer might place the following action on a timeline inside a FLA file:

dispatchEvent(new Event("animationHasFinished"));

Although there is nothing invalid about this approach, it does have drawbacks. For developers, timeline actions are harder to author, adjust, and locate than code inside external ActionScript files. Many designers will also find this approach too technical. Lastly, it simply violates the principle of keeping your actions and timelines separated (yes, we "Flashers" are proud people).

At Refunk, where I work, we have developed a small utility that elegantly solves this problem. The TimelineWatcher class enables a developer's code to watch a timeline as it is played back and be notified when a frame label or the end of the timeline has been reached. By using frame labels as hooks—cue points, as in web video—timelines and actions can now be truly separated.

The TimelineWatcher and TimelineEvent classes

The TimelineWatcher class is a small, simple utility class. Here is the full documentation:

Package: com.refunk.timeline

Class: public class TimelineWatcher

Inheritance: TimelineWatcher > EventDispatcher > Object

Language version: ActionScript 3.0

Public methods

TimelineWatcher(timeline:MovieClip): Creates a TimelineWatcher object to watch a single timeline

dispose():void: Removes the TimelineWatcher object's internal listeners and references, so it can be garbage collected without any memory leaks

Events

labelReached: Dispatched when a new timeline label has been reached

Event Object Type:

com.refunk.events.TimelineEvent

Event.type property:

com.refunk.events.TimelineEvent.LABEL_REACHED

Custom property/value:

currentFrame: The current frame (int)currentLabel: The current timeline label (String)

endReached: Dispatched when the end of a timeline has been reached

Event Object Type:

com.refunk.events.TimelineEvent

Event.type property:

com.refunk.events.TimelineEvent.END_REACHED

Custom property/value:

currentFrame: The current frame (int)currentLabel: The current timeline label (String)

Because the TimelineWatcher class extends the built-in EventDispatcher class you can add event listeners using the standard addEventListener() method. It goes hand-in-hand with the TimelineEvent class, which is a custom event class that explicitly types the events used by TimelineWatcher. These events additionally store the current frame number and label, so they can be retrieved via the event object.

You can find the TimelineWatcher and TimelineEvent classes in the sample file for this article (timelinewatcher.zip). Both classes are made available as free code by Refunk and are distributed under the GNU General Public License.

Setting up the TimelineWatcher example

To see a working example of TimelineWatcher, start by unzipping the timelinewatcher.zip file and opening index.html in your desktop web browser (make sure you have Flash Player 9 or later installed). You will see a simple timeline animation of a red ball that animates from the left to the right and back. It loops three times before the animation stops. A text field in the top left corner displays the timeline label that is currently playing and the number of loops the animation has made (see Figure 1).

Figure 1. Simple TimelineWatcher example

Open the test.fla file in your Flash authoring environment, and you will see a white canvas with a MovieClip of a red ball (see Figure 2).

Figure 2. Canvas at frame 1 showing a red ball

The main Timeline contains two classic tweens, one that moves the ball to the right and one that moves it back to the left, with two frame (or timeline) labels—moveRight and moveLeft—indicating the direction of the animation (see Figure 3).

That's all the design work that went into the example. When you test this movie—without the attached Document class, as I will discuss next—you will see an endlessly looping animation of a red ball that moves back and forth.

The next step is to add an external ActionScript file that will do the following:

Display the dynamic text field on the top left of the canvas that indicates the current Timeline label and the amount of loops that have been completed

Stop the animation after three loops

To link the external ActionScript file named Test.as to the test.fla file, type Test as the Class in the Publish settings of the Properties panel (see Figure 4). At compile-time this Document class will be associated with the main Timeline, and will be able to provide functionality much like actions on the main Timeline.

Figure 4. Document class field in the Properties panel

Before examining the external ActionScript file, there is one additional setting you need to be aware of. Choose File > Publish Settings and click the Flash tab. Make sure ActionScript 3.0 is specified in the Script menu and click Settings to open the Advanced ActionScript 3.0 dialog box (see Figure 5).

By default the Automatically Declare Stage Instances check box is selected, which means that Flash will automatically declare any element with an instance name that resides on the main Timeline at compile time. Although this is a handy feature for designers and developers who use the Flash authoring environment for ActionScript development, it also can cause problems for developers who use external code editors, because these editors will complain that these declarations have not been created. (Flash acts as if they have been created—it kind of creates them for you in memory—so it's not really a matter of visibility; they are required but don't exist, and Flash creates them for you automagically.)

To make your code editable in multiple development environments, you are better off unchecking this option and explicitly declaring every element with an instance name that resides on the main Timeline as a public class variable in your Document class. Without these declarations, Flash will throw a compile-time error. In the example there is just one MovieClip on the main Timeline with the instance name ball, so the following declaration is required:

public var ball:MovieClip;

From this point onwards you automatically have a reference to the ball instance on the main Timeline.

The code above declares the ball MovieClip on the main Timeline and stops its playback. Although Flash implicitly calls the super() method in the constructor, I usually add it for all extended classes as a best practice; this reminds me to make the method call when additional arguments are required. Starting with the basic scaffolding above, I add the text field for the current timeline label to the top left of the screen (highlighted text indicates the newly added code):

First I import both classes so the Flash compiler knows where to find them. Next I add two constants named MOVE_LEFT and MOVE_RIGHT that match the timeline labels. This is a good practice to avoid errors due to typing mistakes.

Next I declare the TimelineWatcher instance named timelineWatcher as a private class variable. In the main constructor named Test(), I create the actual TimelineWatcher instance and pass it the timeline that I want it to watch as a parameter. In this case I can use the keyword this, because it reflects the main Timeline.

I also add an event listener to listen for the TimelineEvent.LABEL_REACHED event, which triggers the custom handleTimelineEvent() method. Next, I start playing the main Timeline again.

The handleTimelineEvent() method uses the returned event object named e to retrieve the current label and checks if it corresponds with the predefined labels I am monitoring. If so, it updates the timeline label on the screen.

When you run this example you will see the red ball continuously moving back and forth with the current timeline label in the top left of the canvas. After adding only a few lines of external ActionScript code I now know exactly what's going on with the main Timeline. And, look mum, I used no timeline actions at all!

The edits to the code below stop the timeline after it has played three loops: