By:Mark Angeletti, Published:2006-6-1

At this point we need to talk about searching our XML to locate the values we need. This is a good time to revisit our navigation XML file.

  1. <nav>  
  2.  <button>  
  3.   <image>button1.png</image>  
  4.   <text>Articles</text>  
  5.   <link>articles.swf</link>  
  6.  </button>  
  7.  <button>  
  8.   <image>button1.png</image>  
  9.   <text>Books</text>  
  10.   <link>books.swf</link>  
  11.  </button>  
  12.  <button>  
  13.   <image>button1.png</image>  
  14.   <text>Blog</text>  
  15.   <link>blog.swf</link>  
  16.  </button>  
  17.  <button>  
  18.   <image>button1.png</image>  
  19.   <text>Contact ‘company name’ today …</text>  
  20.   <link>forum.swf</link>  
  21.  </button>  
  22. </nav>

In order to retrieve values from an XML file, we step through the family tree until you find the desired value. So in our code, xnRootNode.firstChild.childNodes.length;, the first child, is <nav> and it has 4 child nodes — you guessed it, they’re our 4 <button> nodes. So nTotalButtons is now equal to 4.

Next we use a ‘for loop’ to gather all the data from each of our buttons and add it to our arrays.

astrImages.push(xnRootNode.firstChild.childNodes[i]
.childNodes[0].firstChild.nodeValue);

astrImages is our array for images; the push method adds our XML value to this array.

xnRootNode.firstChild.childNodes[i].childNodes[0]
.firstChild.nodeValue;

This may look scary at first, but let’s break it down.

xnRootNode.firstChild is <nav>, its first child is the first occurrence of <button> and <button>‘s first child is <image>. So far, so good, but what is <image>‘s first child? If you said, "button1.png" then pat yourself on the back: that’s correct. Even the text value within the node is considered a child node in Flash. Lastly, we use the nodeValue property to retrieve the node value of the XML object, in this case "button1.png." Have a look at the image below, as it may help.

We continue to fill in all our arrays, then move on. Only after our XML data has completed loading and has been pushed into our arrays are we ready to move the playhead onward. Now, we move to our next frame.

Frame 3

Frame 3 is used to load our CSS file. Have a look at our navigation.css file:

  1. .buttonStyle {
  2. font-family: tahoma, verdana, arial, helvetica;
  3. font-size: 16px;
  4. color: #000000;
  5. text-align: center;
  6. }

It looks like any other CSS file. We use CSS to set the formatting on our buttons, which just keeps with our paradigm of keeping everything external and dynamic.

Now that our CSS has loaded successfully, let’s move on to frame 4.

Frame 4

Before we look at the code for frame 4, let’s review. When our Flash file loads, it hits frame 1 and sets all the variables that we will need throughout our site. Next, in frame 2, we gather external data. We got a little bonus and learned how to import XML code which we then parsed and stored in 3 arrays that we’ll use in frame 4. In frame 3, we imported the CSS that we’ll use in frame 4.

What I want you to notice is that we’re at our last frame and, at this point, nothing has been built. Up to this point we’ve only gathered the data that we’ll need. We are now at frame 4, where the playhead will rest indefinitely and our Flash file will take form.

We start by tracing our arrays just to reassure ourselves that we have everything we need. If you’re not familiar with the trace() function, then you won’t get far in Flash. Trace() is used to display messages in the Output panel while testing your SWF file. Do a CTRL + ENTER right now and it should pop up the Output panel, displaying the data from our arrays.

for (var i = 0; iRecall that nTotalButtons was set in frame 2 and is equal to 4 — the total number of buttons. Also notice that navHolder_mc is already on our canvas in the navHolder layer.

Now, we use a ‘for loop’ to create our 4 buttons. Within navHolder_mc, we use the createEmptyMovieClip() method to create a movie clip that will hold our buttons.

var navButton:MovieClip = navHolder_mc["navButton"+i];

This creates a movie clip called navButton and sets it equal to your newly created movie clip. This just makes life easier: we can simply refer to navButton, instead of navHolder_mc["navButton"+i], now.

image_mcl.loadClip( astrImages[i], navButton );

We tell the loadClip() method to load the button image (from our array) into the newly created movie clip.

Now, remember that image_mcl was defined in frame 1 as a MovieClipLoader, and MovieClipLoader allows us to implement listener callbacks that let us know when our image has completed loading.

mclListener.onLoadInit = function(target_mc:MovieClip) {

The onLoadInit handler is invoked after the actions in the first frame of the clip have executed, so you can begin to manipulate the loaded clip. This handler is called after the onLoadComplete handler. For most purposes, use the onLoadInit handler.

At this point, we have a new movie clip for our button with our image loaded into it. Now let’s set some properties.

target_mc.linkURL = astrLinks[nCounter];

This attaches a variable called ‘linkURL’ to target_mc movie clip; target_mc is automagically set to the object that called this function; in this case it’s our movie clip button. Don’t believe me? Trace it!

Note: ‘Automagically’ is a technical term for when something happens automatically without you doing anything and you can’t really explain how it happens! Feel free to use it around the office — it will catch on.

Next, we set linkURL equal to the first link in our array.

target_mc.onPress = buttonClick;

This attaches the onPress event handler to our button. In other words, when the button is clicked, it will call the buttonClick function.

var buttonImgHeight:Number = target_mc._height;
var buttonImgWidth:Number = target_mc._width;

We define a couple of variables: one stores our button’s height, while the other stores its width.

target_mc._y = Math.round( yPosition );
yPosition += buttonImgHeight+3;

We move our button’s vertical position (y position) down by 3 pixels each time we create a new button.

target_mc.createTextField( "buttonText", nCounter, 0, 0, buttonImgWidth, buttonImgHeight );

This creates a new, empty text field within our button movie clip. The createTextField() method takes 6 parameters:

createTextField(instanceName:String, depth:Number, x:Number, y:Number, width:Number, height:Number);

Now that we have created a new text field (buttonText), we’re going to assign it a few properties.

target_mc.buttonText.border = false;
target_mc.buttonText.selectable = false;

target_mc.buttonText.wordWrap = true;

The border property for our text field is currently set to false; however, during development I often set this to true, as it makes positioning things a little easier. In addition, we want our text to wrap, but we don’t want it to be selectable.

target_mc.buttonText.styleSheet = my_css;

This line assigns our CSS style, which we imported already. Notice the next line:

target_mc.buttonText.htmlText = "<.buttonStyle>"+ astrText[nCounter] +"</.buttonStyle>";

Here, you can see how to implement our CSS style. Recall that .buttonStyle is defined in our external CSS file. Also notice that we’re using the htmlText property — not just text.

target_mc.buttonText.filters = filterArray;

This line assigns our filter to the text field. Recall that we created a drop shadow filter back in frame 1. If you don’t have Flash 8, you won’t be using any filters.

These next few lines of code are pretty cool; they come in very handy when trying to align text vertically.

target_mc.buttonText.autoSize = true;
var nMiddle:Number = ( buttonImgHeight/2 );
target_mc.buttonText._y = nMiddle - ( target_mc.buttonText._height/2 );

We first set the autoSize property of our text field to true. This allows the text field size to match the height and width of the text that’s placed in it. Next, we find the middle of our button and store it in nMiddle. If we divide buttonImgHeight by 2, we should find the middle of our button. Now we can set the y position of our text field to be in the middle of our button. To do so, take nMiddle and subtract our text field’s height divided by 2.

Now we’ve vertically aligned our text in our buttons dynamically.

nCounter += 1;

We increment nCounter by 1 for each button that’s generated.

image_mcl.addListener(mclListener);

The addListener method attached to our MovieClipLoader object allows it to receive notification when our image is fully loaded.

The last bit of code is our button click event handler.

function buttonClick():Void {
 trace( this.linkURL );
}

This function executes when a button has been pressed. We run a trace on the button’s LinkURL property, which we set earlier. If you CTRL + ENTER to pop up the Output panel, then proceed to click some buttons, you should see the associated SWF file displayed in the Output panel.

This is as far as we’ll go in this article. If we were to continue, the next step would be to load the SWF file using another MovieClipLoader, just as we did earlier for the image files. However, we’ve now done enough to get the point. What is the point? Well, let’s review.

The Big Picture

We’ve achieved a lot in this article. We’ve learned how to import XML into Flash, then parse it and store it in arrays. We learned how to import CSS and assign it to text fields to apply formatting. We also have learned how to use the new filter feature in Flash 8 to apply a drop shadow effect. All this is good, but it’s not the main point.

What I want you to take away from this article is the way in which we structured our Flash site. Everything that makes up our Flash site resides outside Flash: our external XML file holds the text that’s used for the buttons, the image that’s used for the buttons, and the link reference for the buttons. Our external CSS file holds formatting information for the buttons.

Keeping everything outside Flash allows our site to be completely dynamic — we can make changes at any time and not ever have to touch our Flash file. As a bonus, it also keeps our SWF file extremely small and fast loading.

Also, we were in complete control of the Flash playhead the entire time. We moved the Flash playhead to the next frame on our own terms, not Flash’s, which can help to avoid a lot of frustration. Many errors are made in Flash because developers allow the playhead to run wild. We never allowed that to happen; we systematically controlled the playhead. Frame 1 set global variables, then we stopped at frame 2, where we loaded in XML data. Once complete, we stopped at frame 3 and loaded CSS data, and on completion, we stop at frame 4 and build our application.

I hope the principles presented in this article will allow you to better structure your next Flash site.

UPDATE: I have revised the code on frame 4 to handle multiple colored buttons, since many asked for this. It will better handle the order of your buttons now.

You can download the new .FLA file here

All you had to do was in Frame 4 change the code from this:

actionscript

  1. /*
  2. * This frame we will build the navigation
  3. */
  4. stop();
  5.  
  6. trace("Images: "+ astrImages );
  7. trace("Text: "+ astrText );
  8. trace("Links: "+ astrLinks );
  9.  
  10. for (var i = 0; i<nTotalButtons; i++) {
  11.    
  12.     navHolder_mc.createEmptyMovieClip( "navButton"+i, i );
  13.     // make new MovieClip and set to newly created button
  14.     var navButton:MovieClip = navHolder_mc&#91;"navButton"+i];
  15.    
  16.     // load images
  17.     image_mcl.loadClip( astrImages&#91;i], navButton );
  18. }
  19.  
  20. // Invoked when the actions on the first frame of the loaded clip have been executed
  21. mclListener.onLoadInit = function(target_mc:MovieClip) {
  22.  
  23.     // add link property
  24.     target_mc.linkURL = astrLinks&#91;nCounter];
  25.    
  26.     // add events
  27.     target_mc.onPress = buttonClick;
  28.    
  29.     var buttonImgHeight:Number = target_mc._height;
  30.     var buttonImgWidth:Number = target_mc._width;
  31.  
  32.     target_mc._y = Math.round( yPosition );
  33.     yPosition += buttonImgHeight+3;
  34.    
  35.     // place the text on the button and center the text
  36.     target_mc.createTextField( "buttonText", nCounter, 0, 0, buttonImgWidth, buttonImgHeight );
  37.  
  38.     // set properties of textField
  39.     target_mc.buttonText.border = false;
  40.     target_mc.buttonText.selectable = false;
  41.     target_mc.buttonText.wordWrap = true;
  42.    
  43.     target_mc.buttonText.styleSheet = my_css;
  44.     target_mc.buttonText.htmlText = "<.buttonStyle>"+ astrText[nCounter] +"</.buttonStyle>";
  45.     target_mc.buttonText.filters = filterArray;
  46.    
  47.     // center the text vertically in the button
  48.     target_mc.buttonText.autoSize = true;
  49.     var nMiddle:Number = ( buttonImgHeight/2 );
  50.     target_mc.buttonText._y = nMiddle - ( target_mc.buttonText._height/2 );
  51.    
  52.     nCounter += 1;
  53. };
  54. image_mcl.addListener(mclListener);
  55.  
  56. // Event handlers
  57. function buttonClick():Void {
  58.     trace( this.linkURL );
  59. }

to this:

/*
* This frame we will build the navigation
*/
stop();

trace(“Images: “+ astrImages );
trace(“Text: “+ astrText );
trace(“Links: “+ astrLinks );

// build the empty movie clips to hold the buttons
for (var i = 0; i

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators



Random Bits Podcast

You need to download the Flash player from Adobe

Blogs Worth Reading