Developer

XML drives this dynamic Flash MX application download

With the introduction of XML in Flash MX, developers can create more efficient, dynamic applications. To see these features in action, download the source code for this sample app.


The ability to parse XML and rely on XML-driven data in MX opens up Flash’s development potential. With this functionality, you can modify menu items by changing an XML file instead of rehashing your ActionScript.

In this article, we’re going to construct an interface that uses Flash’s animation power to display dynamic content. When we’re finished, we’ll have a small piece that could be used as a product display. You can download the source code for this application here.

What you’ll need
  • ·        Flash MX
  • ·        The source files for this project
  • ·        Intermediate experience in XML and Flash ActionScript

Although it’s a good idea to separate your ActionScript into includes (#include yourFile.as) when it becomes too complex, we won’t be doing that here. Our application is simple enough for us to do most of our coding in the Flash MX environment. When we’re finished, you may decide to extend what we’ve built in various ways. If so, you'll want to keep an eye on your code and split it into external ActionScript files as soon as you feel it’s necessary.

The .fla file
Start by opening Flash MX and loading xml_interface.fla. Your screen should look like Figure A.

Figure A
Your project inside Flash MX


The elements of this small yet potent Flash interface have been placed on the screen and given instance names menu and pages. Let’s work through a description of each to gain more knowledge of the elements that make up our interface.

Navigation
Since our interface is small, we’ll want to conserve screen space to focus the user’s attention on the content. Our interface will contain code for a menu that hides itself after a given period of time elapses. Figure B shows the application window with the menu hidden.

Figure B


Content
The movie clip pages represents the content, as shown in Figure C.

Figure C


The movie clip pages will be duplicated vertically as many times as there are nodes with the name page in the XML file, as shown in Listing A. Inside pages, each individual page clip contains two text fields, one to display the page title and another (with a scroll bar component) to display the page’s text content.

The XML file in Listing A represents a two-level-deep site structure. Our ActionScript will load this file and build itself based on the node values and attributes expressed in content.xml.

Code on the menu
Generally speaking, it’s not good practice to locate your ActionScript code directly on movie clips. It makes it more difficult to keep track of what’s going on, and it makes returning to the project about as pleasant as a second-degree burn. For our purposes, it’s practical to include code on movie clip menu, as you’ll see when you click on it (it’s on the main stage) and view its code, shown in Listing B.

The event handlers in Listing B control the movement of instance menu. You can view them in Flash by clicking on the menu clip on the main stage.

So how does menu know what to do and when to do it? On the main timeline is a function that looks for certain conditions and reports them to the showMenu() and hideMenu() functions that are embedded on menu, as shown in Table A.
Table A
19 this.menuMove = function(x)
20 var mousePos = x;
21 if (mousePos<=20) {
22 // Tell menu to show itself
23 _root.menu.showMenu();
24 } else if (mousePos>=190) {
25 // Tell menu to hide itself
26 _root.menu.hideMenu();

}

}
Lines 19 through 28 on the main timeline define conditions for menu states.

Code on main timeline
On the main timeline, you’ll see a layer labeled actionscript. Click on its first frame. Let’s walk through the code to get a better understanding of what’s going on.

Setting up the arrays and creating the XML object
Since our project relies on XML for both content and structure, we’ll create a few array objects to hold data (page content and page titles). We’ll pull everything we need from the XML file, and the pages will assemble based on the number of nodes returned in the XML.

On line 0, the array positions will hold locations in pixels for movie clip pages. The this keyword allows the code to be easily broken into its own class. In O-O programming, this technique is often used to denote a calling object; here, it’s serving a similar purpose, except it's referring to itself.

In Table B, lines 1 through 3 contain similar arrays for the major content areas in our application. Array titles holds the page titles, while array text holds the text content that will go into scrollable boxes. Array page_content holds all the pages’ XML nodes collectively.

Line 5 marks the creation of a new XML object to contain the nodes in the XML file we’ll be loading. It’s important to do this so we can begin using the native XML properties to make our application come alive.

Line 6 simply tells our new XML object (myXML) to ignore any white space encountered between the XML nodes.
Table B
1 this.positions = new Array();
2 this.titles = new Array();
3 this.text = new Array();
4 this.page_content = new Array();
5 this.myXML = new XML();
6 this.myXML.ignoreWhite = true;
The required arrays and the XML object

Setting variables that need to be available every frame
The movie clip pages needs to move vertically by a certain number of times its own height, depending on which page is currently chosen. To make it animate into position, a function must run continuously to keep pages’ position current.

In Table C, this function keeps the site’s content where it needs to be. As the _y position of pages changes, variable starty’s value changes. Another important variable in this formula, verticalno, is the difference of pagesy and starty. It will be used to animate pages to a new location on line 11.
Table C
8 this.onEnterFrame = function() {
9 starty = GetProperty(_root.pages,_y);
10 verticalno = pagesy-starty;
11 setProperty (_root.pages, _y, starty+(verticalno/6));
12 }

The function executes once per frame, so if your movie’s frame rate is 31 f.p.s., it will execute 31 times. That’s why we want to make sure that this code is as brief as possible! Some would say it’s bad form to make a function like this execute on every frame, but because the impact of this interface depends on the way pages glides from page to page, this controversial use of onEnterFrame is justifiable.

Setting pages’ location on the stage
We’re going to set pages’ _y location on the stage from special links on clip menu (Table D). These links will be in text fields with Render As HTML enabled in the Properties panel. They will use asfunction(), a documented Flash function that allows you to call any function in the application using hyperlinks.

As you already know, pageMove sets movie clip pages location on the stage when it’s hit by HTML-encoded links. It does this using asfunction().
Table D
14 this.pageMove = function(location) {
15 trace(location);
16 _global.pagesy = location;
17 }

Depending on the position of the user’s mouse on the timeline, menuMove triggers either menu’s showMenu() or hideMenu() functions. You may want to adjust menuMove's position numbers to accommodate the area of the interface you want to reserve to run showMenu(). Obviously, a longer distance from your menu activation area on the stage would lend a feeling of increased sensitivity to the interface when used.

Parsing XML
Now that we’ve coded all the functions necessary, let’s dive into the function executed when the XML file finishes loading. It’s a doozy.

Every XML object in Flash MX has an onLoad method. Advanced applications typically use an init() to initialize classes. We’re going to do something similar, only we'll use our XML object’s onLoad. When content.xml finishes loading, the code in Listing C will execute.

Table E takes this particular onLoad apart.
Table E
32 trace("XML Loaded!");
33 _global.allNodes = this.firstChild.childNodes;
34 _global.hidden = true;


36 trace("Total Pages: " + allNodes.length);

Line 32 traces “XML Loaded!” to the Output Window in the Flash testing environment ([Ctrl][Enter]), basically telling you everything’s loaded and the main initialization function is being run.

In lines 33 and 34, allNodes is populated with the first XML node’s children. The global variable hidden, set to true, is used by showMenu() and hideMenu() on movie clip menu. Remember, allNodes represents the entire structure of this application, content and all. We will leverage it to build our content and make it animate.

For each node (or page) in this simple application, the following things happen:

Line 39: Movie clip pages is duplicated and renamed as many times as there are nodes. Each new copy’s instance name includes variable j, making each one unique and totally available to your application.

Line 40: Clip page (1, 2, 3, etc…) is repositioned on its _y every 239 pixels as many times as there are nodes.

Line 41: page (page1, page2, etc.) is given a location property. This means we can populate an array with the clip instance’s location property. We can also load the value into the text we’ll soon be outputting to clip menu’s menu_txt text field.

Line 42: The title attribute of each node is pushed into array titles. This will make each page’s title accessible just as its location is.

Line 43: The same happens here as with the previous line, except now the position property of each duplicated page clip is pushed into an array called, you guessed it, positions.

Now it’s time to go one more level in the XML structure and load menu. In lines 44 through 49, if the node name of each of allNodes’ children is page (which it is), each duplicated pages movie clip’s pageTitle text field is populated with the title attribute of each XML node.

To load menu with each of the page names from the XML, line 46 sets variable linkText to each node’s name attribute. As shown in Table F, menu’s text field menu_txt is set to receive HTML, and menu itself is pumped with HTML-formatted text using our positions array and our linkText variables.
Table F
37 j = 0;
38 while (j<allNodes.length) {
39        duplicateMovieClip(_root.pages["page"], "page"+j, j);
40     setProperty(_root.pages["page"+j], _y, j*239);
41        _root.pages["page"+j].location = -j*239;
42        titles.push(allNodes[j].attributes.title);     
43        positions.push(_root.pages["page"+j].location);
44        if (allNodes[j].nodeName == "page") {
45          _root.pages["page"+j].pageTitle =
         allNodes[j].attributes.title;
46          var linkText = allNodes[j].attributes.name;
47          _root.menu.menu_txt.html = true;
48 _root.menu.menu_txt += "<a href=\"asfunction:_root.pageMove,
"+positions[j]+"\">"+linkText+"</a><br>";
49       }
50       j++;
51 }

The HTML-formatted text contains links, but instead of linking to Web pages, they execute a function on the timeline using asfunction(), mentioned earlier in this article. In line 48, asfunction() passes to the pageMove() function the position of each duplicated page movie clip:
_root.menu.menu_txt += "<a href=\"asfunction:_root.pageMove,"+positions[j]+"\">"+linkText+"</a><br>";

Now we want to populate the cool scroll boxes on each duplicated page clip with the node value of each text node in the XML. First, we have to set up a couple of arrays, as shown in Table G.
Table G
52 for (k=0; k<titles.length; k++) {
53        _root.pages["page"+k].title = titles[k];
54 }
55 for (i=0; i<allNodes.length; i++) {
56        page_content[i] = allNodes[i].childNodes;
57 }

Lines 52 through 54 load every duplicated page clip’s title text field with the corresponding key in the titles array. You’ll recall in line 42, we loaded titles with the title attribute of each node named page.

Next, we load Array page_content with the children of allNodes, which represents all the XML nodes named page (Table H).
Table H
58 // Our first loop begins the dig…for (k=0; k<page_content.length; k++) {
59 // Our second loop makes it serious…for (l=0; l<page_content[k].length; l++) {
60 _root.pages[l].page.contentBox.html = true;
61 // We zero in for the kill…if (page_content[k][l].nodeName == "text") {
62 // Set the HTML ‘cause you never know…_root.pages["page"+[k]].contentBox.html = true;
63 // Load that content!_root.pages["page"+[k]].contentBox = page_content[k][l];
64 }
65 }
66 }

Since we loaded the page_content array with the child nodes (children) of allNodes, we have an array of objects. These objects contain the text nodes we need to deliver to our scroll boxes. Obviously, we need to do a few loops to get at the second dimension of Array page_content, which contains the objects.

Which reminds me—we never loaded the XML. Let’s load it up now:
 
this.myXML.load("content.xml");
 

The result
When published to a test Web page, you should see a smooth-scrolling Flash interface with a yellow background. It's ideal for product displays, even if you don’t have access to a database. Give it a try: Download the code and get started.

 

Editor's Picks