Chapter 15. Components

CONTENTS
  •  Components Overview
  •  Replacing the Component Parameters Panel (or the Properties Panel's Parameter Tab) with a Custom UI
  •  Summary

Components are a sophisticated and convenient way to encapsulate code snippets in a form that can be shared and reused. (They were first introduced in Flash 5 as "Smart Clips.") A Movie Clip becomes a component when you specify the parameters that you want the author to modify in each instance. Effectively, you're just extending the properties by which Movie Clip instances can vary from the built-in set of properties (such as _alpha and _xscale) to include anything you design.

Although you will see very advanced examples of components in the Components panel when you first launch Flash MX, just because components can be very advanced, they don't have to be. For example, you can make a simple component that serves to automate a small portion of just one project. The most important fact to realize is that everyone can make components. (We walk through practical uses for some of the Flash UI (User Interface) components in Workshop Chapter 7, "Adapting Built-In Components.")

In this chapter, you will

  • Learn all the steps involved to turn a Movie Clip into a component

  • Create adaptable parameters that the author can modify when using your component

  • Explore some practical uses for components, such as improving productivity, ensuring consistency, and centralizing code

  • Build custom user interfaces (custom UIs) that serve to replace the generic Parameters tab with one you build in Flash

  • Create Live Preview files so that your component instances will reflect their settings while authoring (without requiring you to select Test Movie)

  • Learn how to distribute and install components so that they appear in the Flash interface

Before beginning this chapter, you should realize that components are used only for authoring. After you build a component, you can use it as many times as you want. You can even share it with others. It makes sense to do so because you might spend a lot of time making the component really useful and adaptable to any situation. Because this means there are two authors, it makes sense to refer differently to the author who builds the original component and the "using author" (that is, the person who uses the finished component while building a Flash movie). After you build a component, you could become the using author. In this chapter, I will distinguish between an "author" and a "using author."

Components Overview

In Chapter 7, "The Movie Clip Object," you learned how to think of variables contained inside clip instances as homemade properties because you access and change them using the same syntax (clip.property or clip.variable). This concept will help when you create components. The process involves specifying which clip variables (homemade properties) the using author can be initialize. An individual component's initial values are set through the Component Parameters panel or the Parameters tab in the Properties panel (see Figure 15.1). Each component instance has a unique starting value for any variable, just as each instance of a clip can have different starting values for any built-in property. Call them "parameters,""variables," or "homemade properties" they're all the same. And, components are adjustable to the using author.

Figure 15.1. The author can specify variables uniquely for every instance of a component by using either the Component Parameters panel or the Parameters tab in the Properties panel.

graphics/15fig01.gif

graphics/icon02.gif

The process of using a component is simple: drag an instance on Stage and set the initial values for the parameters (in either the Component Parameters panel or Properties panel). Then, when the movie plays, it's as though each instance has a different onClipEvent(load) event to assign the values for each variable uniquely for each instance. What's the point? You could just write an onClipEvent(load) script for each instance, and you would avoid components altogether. The problem, however, is that it's a lot more work and the process is less intuitive. (For example, you'd have to remember to include assignments for each variable.) Plus, a fully functioning component takes advantage of two features: a custom user interface (custom UI), which replaces the Component Parameters panel with a Flash movie to guide the using author through populating the data, and Live Preview, which enables the using author to see the populated clip while authoring. If nothing else, a component is an error-resistant method for the using author to specify parameters. For example, he can't accidentally double-click the master symbol and modify it.

Ultimately, a component can make you a more efficient programmer. You can write one block of code that behaves differently depending on the values of the variables that have been initialized through the Component Parameters panel. For example, the component could contain Dynamic Text fields of a specific font and layout. If you have specified the values for the text field variables in the Component Parameters panel, each instance will display different text, but the font and layout will remain the same. This is a perfect example of code-data separation (discussed in Chapter 3, "The Programmer's Approach"). In addition, just like any Movie Clip, if you make a change to the master in the Library (for example, you change the font in the Dynamic Text field), you'll see that change in every instance. In this way, a component can serve to establish consistent text styles.

Another simple example is a component that controls the animation of a ball bouncing. The ball will bounce as many times as the using author specifies for the bounceCount variable. He could have several instances of the same component, but each would bounce a different number of times.

Let's first look at a few basic components, and then we'll look at more advanced, practical examples.

Making Components

Similar to a lot of programming, sometimes it's best to start by hard-wiring a prototype and then come back to clean up things, which makes the code more adaptable. Let's go through some (non-component-related) solutions to making individual clips behave differently.

Solutions That Don't Use Components

First, consider a Movie Clip with a 20-frame animation. In the last frame, place a script that reads as follows:

loopsRemaining--;  if (loopsRemaining>0) {   this.gotoAndPlay (1);  } else {   this.gotoAndStop (1);  }

(We'll keep this script for a few examples.) The first line of the preceding code decrements loopsRemaining by 1. Assuming that the variable loopsRemaining is initialized with a value greater than 0, this script will cause the clip to keep looping until loopsRemaining is reduced down to 0. Notice that if loopsRemaining is 0, the condition is false, so it goes to the else part, where gotoAndStop(1) executes. You can place two instances of this clip on the Stage and use the following script on each instance (not in the clip, but on the instance):

onClipEvent (load) {   this.loopsRemaining=3;  }

Just change the value to which you're assigning loopsRemaining in each instance, and they'll repeat a different number of times.

So far, we don't have a component, and you can see the difficulty of writing the onClipEvent script on each instance. Consider that you might not even need a component but the preceding script is too difficult to trust all your using authors to execute; a component would be more foolproof. Another (less than ideal) solution would be to first remove the entire onClipEvent (previous), name each instance (ball_1 and ball_2, for example), and then from the first frame in the main movie, use a script such as the following

ball_1.loopsRemaining=3;  ball_2.loopsRemaining=5;

We still don't have a component, and you can see this technique has its faults (namely, you have to name each instance and type the preceding script without error).

Finally, remove the script in the first frame so that I can show you one other non-component-related solution. Actually, this solution is not too bad, although it's a lot of work. It lets us explore a clip property that hasn't been mentioned previously: _name. In the first frame inside the master Movie Clip, we can write the following script:

loopsRemaining=_name;

Translated, this says to "set loopsRemaining to the instance name of the clip I'm inside." To use this solution, you'll have to name the clip instances with names such as 1 or 2 (which is a bad idea because you should never start the names of variables, clips, or frame labels with a number). In addition, you'll have to change the script in the last frame to "go to" frame 2 (not 1). Otherwise, loopsRemaining will keep getting reassigned with the previous script. To get around the first problem, you could use a naming convention (such as ball_1) and use a String method (such as loopsRemaining=_name.subStr(5)) to extract just the portion of the name you need. Plus, you should convert the fifth character to a number. And then, the whole thing falls apart if you want more than 9 loops as we're only extracting one digit. Obviously, this is beginning to be a pain and has definite drawbacks, such as the fact that we can't really use the first frame inside the clip and that we have to be careful what we name the instance.

Your First Component

Components offer the same basic features explored in all the preceding solutions but we want the using author to specify the value for loopsRemaining in a very controlled and easy manner (that is, through the Components Parameters panel). It's really quite simple to convert this clip into a component. A Movie Clip becomes a component when you access the Component Definition dialog box. If you first select our Movie Clip that uses the loopsRemaining variable and then choose Component Definition from the Library's Options menu, you'll be faced with the dialog box shown in Figure 15.2.

Figure 15.2. The Library's Component Definition dialog box enables you to specify which variables will be set-able in the component.

graphics/15fig02.gif

From the Component Definition dialog box, you can use the plus button to add variables that will be set-able by the using author. For this example, press the plus button once, click the varName that appears in the Name column, and then type loopsRemaining. Under the Value column, double-click to replace defaultValue with 1 (meaning that if the using author never bothers to access the Component Parameters panel, 1 will be used by default). Finally, leave the Type column in its default setting meaning that the data type for this variable will be either String or Number. (We'll look at the other options shortly.) That's all you need to do, but I want to mention a couple of other options in this dialog box before we move on.

Normally, we want the using author to change only the values of variables, not variable names. The Parameters Are Locked in Instances option will prevent the using author from changing the name of the variables being edited through the Component Parameters panel. Although I can't think of many practical reasons for letting the using author change the name of a needed variable, unchecking Parameters Are Locked in Instances will also allow the using author to add variables (through the Component Parameters panel) that provide an effective alternative to the onClipEvent(load) option I showed earlier.

Another setting of the Component Definition dialog box worth checking out is the Description field. You can use this field to write a concise explanation of how to use the component. You'll have to first click the Set button and then select Description is Plain Text to type a description. It's a good idea to include information regarding how to set each variable. For example, you could say something such as, "Use the loopsRemaining variable to specify the number of times you want the animation to loop." It's sort of funky for the using author because she'll see the description in the Reference panel only after clicking the Help button (in either the Properties panel or Component Parameters panel). (The Description is a Reference Panel option requires that a modified configuration file was installed at the time the component was installed a topic touched on later in the "Distributing Components" section.)

Finally, we'll return to the custom UI and Live Preview features later in this chapter.

Just by adding at least one variable through the Component Definition dialog box, we can turn our Movie Clip into a component evidenced by the new icon in the Library and the fact that the Component Parameters panel is usable and the Properties panel Parameters tab is visible (see Figure 15.3). If you drag three instances of this component on Stage, you can then set loopsRemaining for each one individually very quickly and easily through the Component Parameters panel.

Figure 15.3. When a Movie Clip turns into a component, its icon changes in the Library (as shown in the second one listed).

graphics/15fig03.gif

A Practical Example

Let's build another simple component as a quick review and so that you can see a more practical application: a template. Lay out two Dynamic Text fields with placeholder text: one for a title and one for a subtitle. Make sure that the margins are wide enough to accommodate any likely content and pick a nice typeface. Make sure that the title is associated with a variable title and the subtitle with a variable subTitle (see Figure 15.4).

Figure 15.4. The first practical component that we build will include Dynamic Text fields that we associate to variables.

graphics/15fig04.gif

Select both blocks of text and convert them into a Movie Clip symbol (F8). Confirm that the layout is satisfactory and use the Info panel to notate the x and y coordinates (making sure to use the center point indicated by a black box in the Info panel). Go inside the clip you just created and, in the first keyframe, use the following script to specify the initial location for the clip:

_x=150;  _y=229;

(Use whichever values you found through the Info panel.) Finally, you can make this a component by accessing the Component Definition dialog box. Just add title and subTitle to the Name column for parameters. That's it! Anyone can now drag an instance on Stage and define the content through the Component Parameters panel, and the layout will be perfectly consistent. You can even make a global edit to the layout or font style by editing the master symbol. All the instances in use will retain their values for title and subTitle. (By the way, you'll need to Test Movie to see anything other than your placeholder text in the two fields a fact that we'll overcome when we cover Live Preview.)

Other Data Types

Before we move on to some advanced examples of components, let's quickly explore the alternatives to the Default data type found when populating the Component Definition dialog box (refer to Figure 15.2). The other data types are Array, Object, List, String, Number, Boolean, Font Name, and Color.

When you want the using author to populate the clip's variables with strings or numbers, just leave the Type option set to Default. Flash will figure out whether the using author supplied a Number, String, or Boolean data type, and treat it accordingly. You can force Flash to treat the value provided as a String data type or a Number data type. This can be nice when you want "2" to be treated as a string. (Flash would normally convert it to a number if you left the data type set to "Default.") Selecting Boolean is kind of cool because the using author will see a drop-down menu from which he can choose only true or false. Realize, however, that setting the data type to String or Number will still permit the using author to type in the wrong data type, and then Flash will consider the value to be undefined.

Three of the remaining five data types (Array, Object, and List) are similar in that they enable the using author to supply multiple values for a single parameter's value. The List data type is unique because it really isn't a data type per se. Think of this option as a "drop-down list" where the using author can select from a pre-designated drop-down list that you define. This option enables you to control the using author's input. For example, maybe you want to give the using author a choice among "Jazz,""Rock," and "Classical" for a component that plays music, and those are the only three options available. If you leave the data type as Default, he could enter "Disco" or something that you hadn't expected. When you opt for the List data type, you also need to populate the drop-down list by double-clicking the cell in the Value column (listed as "<none>" by default). The Values dialog box will appear (see Figure 15.5). Click the plus button for each new item, and be sure to click the little check box to indicate the default value (which is selected if the using author never makes a selection).

Figure 15.5. Selecting the "list" type in the Component Definition dialog box (top) gives the using author a limited choice (in the drop-down list at the bottom) when populating component instances.

graphics/15fig05.gif

Realize that once the using author selects from the drop-down list you populated, the value for the parameter will simply be the item selected in the drop-down. That is, if the using author selects first (from Figure 15.6), the myParam value will be the string "first". If the using author selects 123, the value of myParam will be the number 123. In this way, the List data type is similar to the Default data type, except you allow the using author to select from a list.

Figure 15.6. The default data type will automatically turn values into strings or numbers as appropriate.

graphics/15fig06.gif

The Array data type is a bit more straightforward. Here, you give the using author the capability to populate the parameter with as many values as she wants. For example, the ComboBox Component that ships with Flash uses this option to enable the using author to add as many items as she wants. If you prefer, you can pre-populate the array (through the Values dialog box not unlike the one shown in Figure 15.5). However, the using author will still be able to add or remove items from the array. In addition, the parameter will have the Array data type, so the component's code will need to access values according to how arrays work (such as using brackets to reference individual items in the array).

Finally, the Object data type should be familiar to you. (We've explored generic objects as a storage mechanism.) Here, the parameter will have multiple named values (rather than just multiple values, as in the case of the Array data type). Also, the using author won't be able to add named properties to the object; he'll only be able to set the value for each property. Perhaps you designed a component that requires a generic object to pass to the Color object or, maybe you've just fallen in love with storing values in named properties. The Object data type enables you to store multiple values in a single variable (with named properties). Just like with the Array or List data types, you'll want to pre-populate the property names (and default values for each) by using the Values dialog box.

graphics/icon02.gif

Before we discuss more practical uses for each data type, let's look at the remaining two choices: Font Name and Color. These are probably the two most convenient improvements that components have over their "Smart Clip" ancestors. The Font Name data type displays a drop-down list to the using author with all the fonts on his computer (see Figure 15.7). This can be convenient when your component uses the TextField or TextFormat objects (covered in Chapter 10, "Keyboard Access and Modifying Onscreen Text").

Figure 15.7. You can present the using author with a selection of the fonts installed on his system.

graphics/15fig07.gif

The Color data type gives the using author a standard Flash Color Selection dialog box (including the dropper cursor, which can point to any color onscreen). For a super-simple application, draw a shape, convert it to a symbol, and then access its Component Definition dialog box. Add a parameter with the name myColor and the type Color, and then click OK. Go inside the master symbol (you'll want to double-click the Library item) and place the following code in the first keyframe:

temp_color=new Color(this);  temp_color.setRGB(myColor);

The first line instantiates a Color object in the temp_color variable that's linked to this clip instance. The second line does a setRGB() on the temp_color object using the myColor variable as the parameter. Drag a few instances on Stage, and then use the Properties panel (Parameters tab) to set the color for each instance. It's pretty convenient, isn't it? You'll see more examples later in this section, but this should give you a taste of how easily you can gather color information from the using author. By the way, the value for the myColor variable will range from 0 to 16,777,215. You can use the following formulas to convert this number to a Hex or RGB value.

graphics/icon01.gif

To express a base 10 number as a Hex string:

myNumber.toString(16);

For a practical use of this formula, place the code trace(myColor.toString(16)) in the first frame of a component that lets the user define myColor (as in the code above that exemplifies the Color data type).

To extract the standard values (0 255) for red, green, and blue from a given base 10 color value (0 16,777,215) shown here as myColor:

var r=Math.floor(myColor >> 16);  var g=Math.floor(myColor - (r << 16) >> 8);  var b=Math.floor(myColor - (g << 8) - (r << 16));

Notice that the formula for g assumes that r has previously been assigned the correct value (and, b assumes both r and b have been assigned). If you want, you could just take the whole formula for r and replace the r in g's formula although it would get pretty ugly. To reveal the RGB value, add the preceding lines to the component's keyframe, followed by this trace statement:

trace("R: "+ r +", G: "+g+ ", B: "+b);

Before I get carried away with the Color data type, let me show you one last option before we review and move on. The Component Definition dialog box has a column for both "Name" and "Variable." The using author will always see the Name column, and it will appear to him that he is setting its value. Actually, if you leave the Variable column blank, the using author is setting the value for whatever variable is listed under the Name column. It's possible to further separate the using author from the code behind the scene, however. For example, maybe you want to create code that refers to a variable name that might be cryptic to the user. Maybe myColor doesn't really make sense to a novice using author. You can still use myColor inside the component, but let the using author think that he is setting a value for "my favorite color" (which is not a legitimate name for a variable). Simply put, your actual variable in the Variable column and the wordy name for the using author to see in the Name column (see Figure 15.8).

Figure 15.8. You can insulate using authors from your cryptic variable names by providing a "name" that they will see. (Notice that myColor doesn't appear in the Properties panel.)

graphics/15fig08.gif

As a quick review, we've seen that a component is simply a Movie Clip for which the Component Definition option was used to specify parameters that the using author will be able to manipulate. You also have plenty of choices as to the format for that parameter (Array, Object, List, String, Number, Boolean, Font Name, and Color). Each of the options affects the way and type of values the using author gets to supply. One would suspect that you'll be using those variables somehow inside the clip such as within a Dynamic Text field or in a script that utilizes the value of the variable. Each instance is unique in all the ways the different clip instances can be unique; but, in addition, the using author can change the value of all variables listed in the Component Parameters panel. In this way, the using author makes each instance of a component behave differently because each instance will start off with different values for all its variables.

Advanced Applications for Standard Components

Although the previous example (of using a component like a template to impose a consistent font and layout for text) was indeed practical, it was quite simple. Other practical examples aren't quite as simple. I'm going to call the following examples "standard" components (not "simple") because they don't involve the more advanced features (custom UIs and Live Preview). A custom UI replaces the Clip Parameters dialog box (and its rigid-looking Name and Value columns) with a Flash movie that you have to build. It's the job of this other Flash movie (the UI) to set the necessary variables, but it can do so in a very graphic way. The Live Preview is still another Flash movie whose job is to display (during authoring) how the populated component will appear once the movie plays. We'll make both custom UIs and Live Preview files in the following section, but first I want to show some advanced examples of the standard form. You don't need to try to follow along too closely as we explore some of the possibilities.

In Workshop Chapter 3, "Creating a Horizontal Slider," we'll build a slider that lets the user (not just the using author) interact by dragging it from 1 to 100 (see Figure 15.9). After building a somewhat hard-wired version, we'll turn it into a component to allow the using author to specify three properties: the location of 1 (the minimum location for the slider), the location of 100 (the initial location so that the slider can default to a point other than 1), and the name for a function that the slider will repeatedly call as the user slides the slider. Using a function makes it possible for the slider's value to be used to modify anything on the Stage from another clip's alpha level to the overall sound level. A function that a component calls (back in the main movie) can be referred to as a callback function.

Figure 15.9. In Workshop Chapter 3, we'll turn a slider into a component so that it can be reused.

graphics/15fig09.gif

In Workshop Chapter 9, "Creating a ToolTip Component," we'll build a component that will enable the using author to specify the exact string of text that should appear when the cursor rolls over another object. The using author will be able to drag as many instances of this tooltip component as she wants.

Finally, here's an example of a component that I built for use in a real project. I used Flash in a presentation, but wanted another version (that the audience could download) that included speaker notes. The content for the notes would be loaded in from an external file (as you'll learn about in Chapter 16, "Interfacing with External Data") because it wouldn't be written until later plus, I wanted to be able to modify it at any time. Anyway, I made a component not unlike the tooltip described previously, but rather than making the using author (me) specify all the text, I simply specified the section and subsection where it was being used. The loaded data included details as to which section and subsection it applied to, so my component simply displayed (similar to a tooltip) the data appropriate for that section. The result was that users could view the presentation and optionally click a Speaker Notes button to see additional information (see Figure 15.10).

Figure 15.10. In an actual project, I made a component to display the appropriate speaker notes.

graphics/15fig10.gif

Although these examples are not the only things possible with standard components, I just wanted to make a point that you often don't need to build custom UIs or Live Preview files.

Replacing the Component Parameters Panel (or the Properties Panel's Parameter Tab) with a Custom UI

One of the most intriguing features of components is the fact that you can assign an interactive Flash movie to play inside, and effectively replace, the Component Parameters panel (or the Properties panel's Parameters tab). The process involves first building a Flash movie, exporting it as an .swf, and then pointing to the .swf through the Component Definition dialog box. You'll have two files: an .fla file with the master component in a Library and an .swf that plays inside the Component Parameters panel. The .swf is called a custom UI, and its filename is specified in the Custom UI field (see Figure 15.11).

Figure 15.11. The Custom UI field of the Component Definition dialog box points to an external file that will be used in place of the Component Parameters panel.

graphics/15fig11.gif

By replacing the Component Parameters panel, we have the opportunity to make something more usable. But most components are perfectly suitable without a custom UI. So instead of leaping straight into building custom UIs, we'll first look at how to design them so that we're sure to use them appropriately. You'll see that building a custom UI can be somewhat involved so it makes sense to make sure that they're necessary.

Designing Custom UIs

Naturally, the process of creating a custom UI is purely technical. To make a good custom UI is another matter. I think it's fair to say that the only time to create a custom UI is when the built-in Component Parameters panel is inadequate. There are many situations in which this could occur. For example, making the using author set several variables through the standard Component Parameters panel could be unreasonably tedious. In this case, an easier solution might be a graphic selection device, such as a slider. Or, if he's selecting sounds, you could include a short audio sample. Finally, a perfect situation for a custom UI is when there is a series of complex selections the using author must make. You could build a custom UI that served as a wizard walking the using author through all the steps involved and even providing online help where appropriate. A good example of this approach can be found in the components included with Flash's Learning Interactions Library (under Window, Common Libraries).

After you've determined that a custom UI is appropriate, you can take steps to design how it will function. The most important consideration is usability. Because the purpose of the custom UI is to provide some benefit not found in the standard Component Parameters panel, you should make sure to make it easy for the using author. I suppose if you're building a component for your own use, you can invest less time designing it (at the expense of usability), but in such a case you probably won't want to build a custom UI at all.

As it turns out, one of the most critical features that will make your custom UI more usable happens to be one of the most difficult to program. It's important for the custom UI to always indicate the current settings. For example, every button should include a highlight to indicate that it's been selected. This highlight should not only provide a clear indication at the time a selection is made, but also the using author should be able to return to the Component Parameters panel and easily ascertain the current setting. After all, she might have several instances of the component and want to check the setting of each one. This round-trip feature (being able to leave and come back to a component) is the difficult programming task. You'll see how to program it in the next section, but realize that it's also a matter of design how you choose to treat the graphic solution. Ultimately, making an intuitive custom UI takes more skill and creativity than just programming it.

Building Custom UIs

Assuming that you've determined a custom UI is really necessary and you have a decent design, you can move on to really building it! First let's make a very simple custom UI, and then add some features. The concentration of this example is on making the custom UI, but we'll need a component for which the custom UI sets properties. You can use the simple bouncing ball Movie Clip that we used in the "Components Overview" section earlier in this chapter. You'll want to create a file (maybe called "host.fla"), make sure it's saved, and then place the following script in the last frame of the Movie Clip:

loopsRemaining ;  if (loopsRemaining) {   gotoAndPlay (1);  } else {   gotoAndStop (1);  }

The job of our custom UI will be to set the loopsRemaining variable. (Arguably, this component doesn't really need a custom UI; we're just doing it for practice.) Make sure that your Movie Clip is a component by using the Component

Definition dialog box to specify that loopsRemaining is setable by the using author. Finally, click the Set button adjacent to the Custom UI field, and then select "Custom UI in external .swf file" and type myUI.swf in the Custom UI .swf File field (see Figure 15.12). You can also click the Browse button and point to a file. However, besides the fact that we haven't made the UI yet, this feature always produces an absolute path where for most situations the relative path we typed in is more desirable. (By the way, in a workgroup situation, you could keep the custom UI in an absolute path on a server for everyone to share.)

Figure 15.12. Replacing the Component Parameter panel or the Properties panel's Parameter tab is as easy as identifying a file to use.

graphics/15fig12.gif

The Custom UI dialog box has a few options that aren't discussed in this example but that are worth exploring. Specifically, the Display options enable you to replace either the Component Parameter panel or the Properties panel's Parameter tab. If you do opt for the Properties Inspector option (that is, the Properties panel), realize that the size provided is 406x72 pixels. The Type choice between "external" or "embedded" is really not terribly complex. Leaving the .swf external will mean that you can edit and re-export the .swf, and the latest version (residing externally) will always be used. Embedding is slightly more convenient because when distributing (to share) the component, you won't have to keep track of two separate files. However, if you need to make an edit to the original custom UI, the "embedded" option requires that you click the "Update" button (which will remain disabled for all Type options other than embedded). Like I say, although this dialog box is fairly intuitive, it's still worth studying. You'll see a very similar dialog box when you make Live Preview files.

Now create a new file and save it as "myUI.fla" in the same folder as the host file. Finally, we can program it. Because we're basically replacing the standard Component Parameters panel, we need to do what it was doing: setting variables. The only catch is that the variables that get exchanged with the host movie's component need to reside in a generic object variable with the name xch. You can have other variables in the UI file, but only the ones in the xch object will become part of the component in the main movie. You can think of the xch object as a surrogate of the actual component; it will contain the necessary variables.

We can make the fastest custom UI in history by creating an Input Text field associated with the variable loopsRemaining and then selecting the text block and converting to the Movie Clip symbol. Finally, just make the Movie Clip's instance name xch and export the movie as myUI.swf in the correct folder. Go back to the host movie and test it out by dragging two instances of the component. In the Clip Parameters panel, you should see the Input Text field where you can specify a number of loops. Also, notice that you can keep the Component Parameters panel open while you alternatively select the two component instances on the Stage. Each should retain its loopsRemaining value. It's easy, really. Although it might not seem as though we created a generic object named xch, we effectively did the same thing by making a clip with the instance name xch. You could reference the loopsRemaining variable as xch.loopsRemaining the same as if you had an object called xch.

Even if we try to spice it up with gratuitous effects (such as text color), this custom UI is pretty simple. Let's start over so that we can encounter something more challenging. In a new file, create a Dynamic Text field in the main timeline and associate it with the variable showLoops. Also, make a button and create four instances in the main timeline, lined up vertically. Place the following script in each button (changing the 1 to 2, 3, 4 for each button, respectively):

on (release) {   pickLoop(1);  }

In the first keyframe of the main timeline, enter the following function:

function pickLoop(whatNum){   _root.xch.loopsRemaining=whatNum;  }

This achieves the task of changing the loopsRemaining variable (well, the loopsRemaining property of the xch object variable) to whichever value is passed from the buttons that call pickLoop(). We can export the .swf, and it should work almost. When we test this from the host movie (the place where we should be testing this), two significant problems arise. First, upon making a selection, the user is not given any graphic feedback as to which button was pressed. The other problem is that when a user returns to view the current setting in a component, he has no clue what the value is for loopsRemaining. (However, it should be noted the component does work as far as letting the user set the loopsRemaining variable.) We can produce a highlight on the currently selected button by creating another Movie Clip in the main timeline and calling the instance arrow. Then we just need a script in the pickLoop function to change the _x and _y properties of arrow. Just name each button instance "button_1,""button_2," and so on, and then add the following code to the pickLoop function:

arrow._x=this["button_"+whatNum]._x;  arrow._y=this["button_"+whatNum]._y;

This simply sets the arrow's coordinates to match the correct button instance. Because we don't know the exact name of the button, we build a string expression ("button_"+whatNum) in brackets preceded by the path to the instance.

Provided that we re-export the myUI.swf, the custom UI should function as far as indicating a selection after we make it, but it still fails to appear with arrow in place upon returning to a previously edited component instance. All we need to do is place the following script in an appropriate keyframe so that it executes every time a using author returns to edit the Component Parameters panel:

pickLoop(_root.xch.loopsRemaining);

Basically, this script sends the current value of loopsRemaining (which is in the xch clip) to the pickLoop function. The problem with our custom UI is not that loopsRemaining is being lost (if we test it, we'll find that it is still there), but that the value of loopsRemaining is unknown when returning to the clip. However, if we place the preceding script in the first frame, it won't work! The issue is that Flash needs some time to send the variables from a component instance to the Component Parameters panel and then to our custom UI. The solution is to move everything in our custom UI out past frame 1, and then invoke a function call (similar to the previous). We'll probably want a stop() command in that frame too. Basically, everything has to move out past frame 1. It's not that funky when you consider the sequence of events: the user clicks a component that has a previously set variable, it invokes the Component Parameters panel, which then launches the custom UI .swf, and then the component tells the custom UI the value of its variables. We just want to make sure that the custom UI waits until frame 2 before trying to use any variables.

Here's the finished code that goes in frame 2 of the custom UI:

pickLoop(_root.xch.loopsRemaining);  function pickLoop(whichNum){    _root.xch.loopsRemaining=whatNum;     arrow._x=this["button_"+whatNum]._x;     arrow._y=this["button_"+whatNum]._y;  }  stop();

Just remember to name the button instances so that nothing shows up onscreen until frame 2. (Also, invoke the pickLoop() function from each button.) By the way, my code is pretty sloppy in that I start referring to and assigning values to properties in the xch object before formally instantiating it (as in xch=new Object()). It just so happens that when an .swf is played as a custom UI (that is, within the Component Parameters panel), the xch object is automatically instantiated. It even has all the named properties and default values based on settings made during the Define Component stage.

Although this example is admittedly simple, a more complex custom UI will have the same elements. You always need to access and set the component variables through named properties in the xch object. And, unless your only means for the user to see his current settings is a Dynamic or Input Text field, you'll need to initialize such highlights somewhere other than the first frame. After you understand these minimum features, you can move on to making more complex components and custom UIs.

Building Live Preview Files

Components don't "do their thing" until you select Test Movie. It's now possible, however, to create a separate file that serves as an author-time preview of how the component will look. In the case of the template component that we built earlier (in the "A Practical Example" section), the using author could populate the title and subtitle variables via the Component Parameters panel, but she wouldn't see her text onscreen (not until she tested the movie). A Live Preview file will resolve this limitation.

A Live Preview file is similar to a custom UI in that it's a separate file exported as an .swf to which the Component Definition dialog box points. However, its job is to visually represent the forthcoming result of any setting the using author makes to the component instance. It makes the most sense when your component is simply a graphic that appears static. The Live Preview file in this case just needs to display the graphics as they will appear for the component. If your component is more involved perhaps containing interactive or moving elements the Live Preview is not just more work, it's less appropriate. Consider that when you drag onto the Stage a component instance that has a Live Preview file on the Stage, you'll actually be watching the Live Preview not the actual component clip. Then, any time you make a change via the Component Parameters panel, you should immediately see that change reflected on the Stage (really, in the Live Preview). It's just sort of hard (or even distracting) to show something that's moving on the Stage while you're authoring.

Creating a Live Preview file is not all that difficult. Logically, it should contain the same basic elements found in the actual component. The hardest part is making sure the registration is maintained. Follow these steps to make the template (from our earlier example) to utilize a Live Preview file.

First, make the component. Start a new file and save it into a known location. Create two Dynamic Text fields: one associated with the variable title and the other with subTitle. Draw an unfilled box around the text to represent the full size of the template. Use the Info panel to reset the box's width and height to a nice round number. (This will correspond to the Live Preview file's document dimensions.) Select just the box and convert it to a Movie Clip, and then set the instance of this box on the Stage to have an alpha level of 0 (via the Properties panel's Color Styles option). Select everything (the two blocks of text and the now-transparent box instance) and convert to a Movie Clip, making sure to select the top-left default center point, which will help keep things registered. Finally, convert this Movie Clip to a component by selecting Component Definition from the Library. Add two parameters: one for title and the other for subTitle. Leave all the defaults except for Live Preview, and then press the Set button. From the Live Preview dialog box, select the option "Live Preview in External .swf File," and then type template_live.swf into the field (see Figure 15.13). When you click OK, Flash will warn you that this file doesn't yet exist (but that's okay because we're about to make it).

Figure 15.13. We'll identify the Live Preview file for this component (and then build it later).

graphics/15fig13.gif

To make the Live Preview file, first enter the master version for the component (via the Library). Select everything onscreen (including the transparent box) and copy. Start a new file and paste. Be sure everything is still selected and use the Info panel's top-left option to align everything to the top-left corner of the Stage. (You can type 0, 0.) Now set the Live Preview's stage size by accessing Modify, Document (Ctrl+J). Set the size to match the dimensions you set for the box. Save this file as "template_live.fla" in the same folder as the component file. Wow, that was just the structure! Now let's discuss the actual code.

The way you make the Live Preview file update any time the using author changes a component variable is by using the onUpdate() function. Basically, whenever the using author makes a change, Flash tries to invoke the function called onUpdate() inside the Live Preview file. All you need to do is put code that handles the refreshing within this function. To apply this to what you just built, simply enter the following code into the first frame of the template_live.fla file:

function onUpdate() {      this.title=this.xch.title;       this.subtitle=this.xch.subtitle;  }

Basically, this just says "set the title variable to equal the title variable contained in the xch object" (and the same with subtitle). Although this might seem pretty easy (it is), there's no rule that says your Live Preview has to be so parallel to the component. You could have a bunch of other stuff that happens whenever this function is invoked. Basically, this is where you put any code that you want to be triggered when the using author makes a change. And, remember that all the variables the using author will be setting are contained as named properties in the xch object.

You should be able to test the example I just outlined. You should notice (provided that you have "Enable Live Preview" selected in the Control menu) that any instances of your component on the Stage will accurately display the values for title and subtitle any time you change them. One way to see what's really happening is to set the font color differently in the main movie's source component. Everything will still work, but you'll see a different color while authoring (the original color, because that's what's in the Live Preview) than the latest color in the component when you select Test Movie. Realize that the tedious steps we took with the transparent box were just to keep the registration accurate.

Finally, it's often desirable to make a component that adapts based on its scale. That is, a component can be "self-aware" of how large it's been scaled and then position contained clips differently based on that scale. In addition to being a fair bit of work for the component, the Live Preview file also needs to make such accommodation. The only catch is the Live Preview file must adjust in real time (as the using author scales it) where a component can do all the layout at runtime. You can see a great example of this kind of behavior in the Bar Chart component in the "Flash Charting Components" available from the Flash exchange site (www.macromedia.com/exchange/flash). When there's enough horizontal space, the bar labels appear horizontally. But when there's not enough room, they rotate 90 degrees to appear vertically (see Figure 15.14). This feat is most impressive when you see the Live Preview adjust as you scale.

Figure 15.14. The same component's Live Preview displays labels horizontally (right) when there's enough room.

graphics/15fig14.gif

In order to make your Live Preview automatically adjust any time the using author scales the component, you need to know about listeners specifically, the Stage object's onResize listener. Listeners were covered generally in Chapter 14, "Extending ActionScript," and specifically (as applied to the TextField object) in Workshop Chapter 10 "Creating Timers." Triggering a script in the Live Preview file every time the using author scales the component requires this simple script:

myListener=new Object();  myListener.onResize=function(){ //put code here }  Stage.addListener(myListener);

Just put code that repositions any clips in place of the "put code here" comment. The only thing really funky about using the Stage's onResize listener is that you'll want the .swf's scale mode to be "no scale." That is, when displaying a .swf (in a browser or as a Live Preview) "no scale" means resizing will only change the window size, not the contained clips. It makes sense when you consider that you will be taking care of all the layout as the using author scales the component, so you don't want all the graphics to scale too. Anyway, this call boils down to one extra line of code to accompany the preceding listener code:

Stage.scaleMode = "noScale";

Basically, this ensures the onResize listener works as intended (and is required any time you use onResize.)

Making Components Affect Other Clips

You might have noticed that some of the built-in Flash UI components can be combined with other clips on the Stage. For example, the ScrollBar component will snap to a text field and let the end user scroll that text field. It's actually very simple to make your component snap to another clip.

All you have to do is include, as one of your component's parameters, the variable name _targetInstanceName. In the Define Component stage, just press the plus button and type _targetInstanceName in the Name or Variable column. Then, if the using author has properly snapped a component instance to another object (clip, button, Dynamic Text, or Input Text instance), the value for _targetInstanceName will be a string that matches the instance on the Stage. Even if that instance was never given a name, Flash will give it a default name (such as InstanceName_0). The only thing a bit funky is that _targetInstanceName will store the string version of the instance name. The following formula will convert that string back into a clip reference:

target=this._parent[this._targetInstanceName];

This simply stores (in the variable target) the actual clip reference. Notice that since we just have a string version, it's placed between brackets preceded by the path (_parent in this case). It's pretty simple, really.

Here's a very quick example of what you can do. Select Insert, New Symbol and make it a Movie Clip. In the first frame of this empty clip, enter the following code:

this.onEnterFrame = function() {      this._parent[this._targetInstanceName]._x += 5;  }

This simply assigns a function to occur for the (soon-to-be) component's enterFrame clip event. Inside the function, the target object is addressed and its _x property is increased by 5 pixels every enterFrame. Finally, you just need to select the clip's Define Component option and add a parameter called _targetInstanceName. Then, just take any clip, button, or Dynamic Text instance on the Stage and drag the component on to its center. You'll see that it snaps to the top-left corner of the object (and the _targetInstanceName parameter is automatically filled). Then, for this weird example, the object automatically moves across the screen.

The point is, it's very easy to let the using author snap a component onto a regular clip instance, and the component's code can affect that target clip. In this way, you can truly separate code from data. The code would be in the component, and the data would be any clip onto which the component is snapped.

Summary

This chapter turned out to be more like a workshop chapter and less like many of the earlier foundation chapters. That's because components are more a feature of Flash than a language element of ActionScript.

The concepts you learned in this chapter included how components enable you to give the using author the ability to set initial values for any property, variable, or homemade property you specify. When you access the Component Definition dialog box, the Movie Clip magically turns into a component. From that point forward, each instance on the Stage maintains its own values for the designated properties. The using author can change individual instance properties through the Component Parameters panel. Additionally, if you go through the work to build a custom UI, you can use this Flash movie to effectively replace the Clip Parameters panel. Finally, for the using author, you can make a Live Preview file to display a component's current values in context.

If you're left with any confusion as to the value of components, don't worry; you'll make plenty of them in the workshop chapters. It's not so much that you sit down and decide, "Today I'm going to make a component." Rather, you can build some code and then say, "Hey, this would be way better as a component because it would be adaptable for multiple instances."

CONTENTS


ActionScripting in MacromediaR FlashT MX
ActionScripting in MacromediaR FlashT MX
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 41

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net