Flash Components      Flash Menu      Flash Gallery      Flash Slideshow      FLV Player      Flash Form      MP3 Player      PhotoFlow      Flash CMS      3D Wall      Flash Scroller

Flash / AS

Silverlight

WPF

ASP.net / PHP

Photoshop

Forums

Blog

About

 


FlashComponents
  Galleries
  Slideshows
  Menus
  Design & Effects
  Audio & Video
  User Interface
  Templates

 

 

 

 


Introduction to XML in Flash
       by senocular

Example: Flash MX 2004 Classes Directory
This example will list out the contents of the Classes folder in the Flash MX 2004 install directory. Can you guess the format of this information? Do I even need to ask? Yup, XML. The XML contains the full contents of the Classes folder, each file and folder and each file and folder within those folders and so on until there's no more files or folders left to file or fold. A recursive function (which even includes a loop on top of everything else) is then used to list out the contents of each folder and is re-called on if any item is itself a folder thereby listing its contents. And this happens until there is nothing left to file or fold!

As an added bonus to this example, we'll make the folders expandable and collapsible. This way you're not forced to look at all of the files at once; you can be selective. And we all know selection is a good thing. When all done and through, you get the following end result:.

[ flash mx 2004 classes directory ]

Download ZIP

 

Note: Class Listing Lag

Given the sheer number of icons attached for this example, there will be a little bit of lag when the XML is loaded and the directory listing is created. As a precaution, should you ever decide to create something similar, you may wish to start with all directories closed loading in the icons only when that directory is opened. For simplicity's sake, here, it was just easier to add them all at once.

 

XML Structure
There technically isn't much to the XML that makes up this example. You're dealing with files and directories, each with a name and type where type determines icon. That's basically two different kinds of elements with two different kinds of data. The most important aspect of the XML is the structure. Folders contain files and other folders so folder elements will have file and folder element children. Directories within other directories can too have their own files and directories and so on and so forth. So what you get is a lot of nested directories. Here's the XML:

mx04_classes.xml

It should look a little something like the following (the entire file is not shown here):

<?xml version="1.0"?>
<directory name="Classes" type="directory">
<file name="Accessibility.as" type="actionscript" />
<file name="Array.as" type="actionscript" />
<file name="AsBroadcaster.as" type="actionscript" />
.
.
.

Starting from the classes directory in a Flash MX 2004 install, you get a listing of all the files and directories that are within complete with name and type.

To generate this list, I used this simple PHP script:

<?php
function ExportDirectoryXML($base, $indent){
if ($dir = @opendir($base)){
while ($file = readdir($dir)){
if ($file{0} != "."){
if (is_dir($base . "/" . $file)){
echo "$indent&lt;directory name=\"$file\" type=\"directory\"&gt;\n";
ExportDirectoryXML($base . "/" . $file, $indent."\t");
echo "$indent&lt;/directory&gt;\n";
}else echo "$indent&lt;file name=\"$file\" type=\"actionscript\" /&gt;\n";
}
}
closedir($dir);
}
}
 
$directory = "[DIRECTORY PATH GOES HERE]";
 
echo "<html><body><pre>\n";
ExportDirectoryXML($directory, "");
echo "\n</pre></body></html>";
?>

This generated the directory structure in markup which I then saved it to a XML file. It's that file which is loaded by the Flash movie (the movie loads a files separate from the script though such a script could be used to load XML like this dynamically from a server). If you'll notice, it uses a recursive function as well.

Preparing the Flash File
This Flash file is really no more complicated than the others before it, at least not in setting up. Scripting is a little more involved. Otherwise, in terms of screen elements, you're not dealing with much more than about 3 different elements: a movie clip for containing the full file listing, an attached clip to represent a directory item (a file or directory), and a scrollbar.

The other two parts are the directory items and the movie clip to contain them. The movie clip used to contain them is just an empty clip called listing_mc. Nothing much in terms of preparation goes into that. However, to keep it masked, it is placed under a graphic that hides content scrolling inside. listing_mc itself isn't masked masked, it's just being hidden by being beneath this graphic.

[ listing_mc beneath movie graphic interface ]

Next it's just a matter of making the movie clip that is to be attached and representative as a directory item. This will be used for both files and directories when added to the listing_mc. This movie clip has three parts: an icon, a text field for a name, and an underlying button used to select it. This example uses the button to open and close directories only, but ideally it would add interaction to the files as well.

[ item mc for each directory item ]

Take note that the registration point for this movie clip is in the upper left. This will be important later on when positioning each item in the display. This will be linked as "directory_item" in the library so that it can be attached dynamically when needed.

Since this is used for all directory items, files (of any kind) and directories, it will need to facilitate the needs and differences of each. The text field is no problem since, as dynamic text, it can be changed easily at any time. The icon, however, is a little more difficult. The icon is actually another movie clip with its own collection of frames inside. These frames contain each of the icon graphics needed for the file listing, the first frame being a directory. For this example, there's only one other file type so frame 2 is an ActionScript file icon. Each frame also has a frame label named after its icon type. This allows navigation to any particular icon much more straight forward using a name rather than a number. This name, conveniently, should reflect the string used to identify type in the XML document.

[ label frames for each icon based on type in xml ]

 

Now, whenever one of these clips is attached as a directory item, it can be given a name and have its icon switched to whatever type is necessary.

ActionScript
For the most part with this example, you get another squirrel finder script-wise. This too revolves around generating a list of movie clips or buttons based on XML. However, here, recursive functions are going to be used to allow directory listings to be created for each other directory within another directory listing. So it's like taking the squirrel finder and change some of its buttons to be other instances of a squirrel finders.

The most difficult aspect of the file listing is arranging the items in the view. Because of the ability to open and close directories, it means that whole groups of items will have to move either up or down in response to more items being displayed from the opening or closing of directories. Instead of attaching items using a variable to control spacing, a new technique is used. This technique positions based on bounding area moving lower items to the bottom of the items above them. This way, should any items be added or removed, basically, you just move the item directly below that change where all items below it can just reposition themselves based on where they should be in respect to the the position of item above them.

We'll get to that script in a second, but first lets look at the definition of the XML instance.

var directory_xml = new XML();
directory_xml.ignoreWhite = true;
directory_xml.onLoad = function(success){
if (success){
GenerateFileListing(this, listing_mc);
scrollbar.setTarget(listing_mc, view_mc._y, view_mc._height);
}else trace("Error loading XML file");
}
 
directory_xml.load("mx04_classes.xml");

The directory_xml variable represents the XML instance. It loads "mx04_classes.xml" using load and has an onLoad which, upon success, runs a function called GenerateFileListing passing in itself and the listing_mc (and of course there's that scrollbar action in there too).

GenerateFileListing(this, listing_mc);

As you might imagine, GenerateFileListing creates a listing of files based on xml (this) in a movie clip (listing_mc). Here is what GenerateFileListing looks like:

function GenerateFileListing(directory_node, target_mc){
var directory_mc = target_mc.createEmptyMovieClip("directory_mc", 1);
SetAtBottomOfParent(directory_mc);
directory_mc._x += item_indent;
directory_mc.depth = 0;
 
var contents = directory_node.childNodes;
var item_mc, last_item_mc;
for (var i=0; i<contents.length; i++) {
 
item_mc = directory_mc.attachMovie ("directory_item","item"+directory_mc.depth, directory_mc.depth);
directory_mc.depth++;
 
item_mc.name_txt.text = contents[i].attributes.name;
item_mc.icon_mc.gotoAndStop(contents[i].attributes.type);
 
if (last_item_mc == undefined) directory_mc.firstChild = item_mc;
else item_mc.previousSibling = last_item_mc;
last_item_mc.nextSibling = item_mc;
last_item_mc = item_mc;
 
if (contents[i].attributes.type == "directory"){
item_mc.select_btn.onPress = Fold;
GenerateFileListing(contents[i], item_mc);
}
 
ArrangeContents(directory_mc);
}
}

 

The basic break down is as follows:

  1. create and position an empty movie clip to hold the directory's contents
  2. loop through the children of the node passed (representing the directory)
    1. attach an item movie clip for each child in that node
    2. assign name and other properties and change icon based on item type
    3. if type is a directory, call the function again passing in the node representing the item and the clip created for it
    4. position the item

Due to the fact that movie clips are being used as directories (and files) and since movie clips can contain other movie clips within them, it seems perfect sense to maintain a directory's own contents by keeping them within that directory's movie clip as child movie clips. However, given that the option of hiding those child movie clips exists, it would be further beneficial to keep all of those child movie clips within one single movie clip (as a child of the directory). That would allow us an easy way to get rid of every single one of those movie clips at any given time simply by removing hiding or that single movie clip in which they all exist.

This is the initial command of GenerateFileListing, creating that empty movie clip for directory contents to exist.

var directory_mc = target_mc.createEmptyMovieClip("directory_mc", 1);
SetAtBottomOfParent(directory_mc);
directory_mc._x += item_indent;
directory_mc.depth = 0;

It does this within the passed target_mc which, initially, is the listing_mc on the main timeline. Other commands such as SetAtBottomOfParent and the assignment of _x (based on item_indent, a variable defined earlier on the main timeline) manage its position while a depth variable is set to manage the depths of clips being attached within.

So right away, when the XML first loads, before listing_mc gets any item movie clips attached to it, it gets an empty clip which is to be treated as a content holder for a collection of directories and files within a directory. This means listing_mc itself only gets one movie clip added to it. All contents within listing_mc end up going in that movie clip. Also, every directory item thereafter will too get its own empty movie clip when a recursive call to GenerateFileListing is made to generate its file contents. What you end up getting is something along the lines of this in terms of movie clip structure:

[ movie clips in movie clips for directory structure ]

Now, if you'll imagine removing or hiding any one of those movie clips holding one of those directory's contents, you can see how the effects would be similar to closing that directory in a directory view which is exactly what we're after.

All that remains is getting the contents in each directory as needed, and that's what the following loop lets us do.

var contents = directory_node.childNodes;
var item_mc, last_item_mc;
for (var i=0; i<contents.length; i++) {
// ...
}

First the child nodes are put into a friendly variable named contents. These are the nodes within the current directory node initially passed into GenerateFileListing. A few other variables being used within the loop are also declared here for safe keeping. Then the for loop is used to cycle through each.

In the loop, each item, directory or file, is immediately created within the directory_mc movie clip (the empty one created to hold all contents of a directory).

item_mc = directory_mc.attachMovie("directory_item", "item"+directory_mc.depth, directory_mc.depth);
directory_mc.depth++;

Then, the text and icon are set for that item.

item_mc.name_txt.text = contents[i].attributes.name;
item_mc.icon_mc.gotoAndStop(contents[i].attributes.type);

This is pretty straight-forward. Simply take the text from attributes the current node of the loop. The text comes from the name attribute and is placed into the name_txt text field while the icon_mc is told to go to and stop on the frame label specified by the type attribute. Directly after this, however, are some assignments that are less obvious.

if (last_item_mc == undefined) directory_mc.firstChild = item_mc;
else item_mc.previousSibling = last_item_mc;
last_item_mc.nextSibling = item_mc;
last_item_mc = item_mc;

What we have here is actually the borrowing of naming conventions used by XML to help handle the movie clip positioning of child movie clips within a directory. Since item movie clips have to be aware of their preceding item in order to position themselves to it, a reference to that item is added within the movie clip. This is defined as previousSibling and handled through the last_item_mc variable defined prior to the loop which following this assignment becomes the current item. Similarly, nextSibling is used to be able to start at the top of a list of directory items and work our way down in order to perform the positioning of each in the correct order. This will work much in the same way the alternative approach to the squirrel finder example did. The directory_mc too gets a reference to a movie clip, the first in the list (when last_item_mc is undefined, it means the current item is the first) in order to be able to start a chain of positioning beginning with it's first item listed. Putting this into motion is handled by four other functions that are used for directory opening and closing.

Next in the loop is the recursive call, or at least the check to see if a recursive call to GenerateFileListing is needed. When it is needed is when the type of the current item is of type "directory."

if (contents[i].attributes.type == "directory"){
item_mc.select_btn.onPress = Fold;
GenerateFileListing(contents[i], item_mc);
}

If so, a button action is added (using Fold, covered shortly) and the call is made. This particular call to GenerateFileListing uses the current node in the loop and the current item movie clip. Each exists within the previous arguments passed in to GenerateFileListing during the current call. So here, and in many cases, the nesting of the function calls reflects the nesting of the objects in which it affects.

[ generatefilelisting called for each directory ]

After each child is created, and if a directory all its children or contents are created, then it is positioned with a final

ArrangeContents(directory_mc);

 

And that brings us to those functions used to handle item position and directory opening and closing. They are as follows:

function SetAtBottomOfParent(below_mc){
if (below_mc._parent._height) {
below_mc._y = below_mc._parent.getBounds(below_mc._parent).yMax;
}
}
function SetBelow(below_mc, top_mc){
if (top_mc != undefined) {
below_mc._y = top_mc.getBounds(top_mc._parent).yMax;
}
}
function ArrangeContents(directory_mc){
var item = directory_mc.firstChild;
if (item != undefined){
while (item = item.nextSibling){
SetBelow(item, item.previousSibling);
}
var parent_container = directory_mc._parent._parent;
if (parent_container != undefined) ArrangeContents(parent_container);
}
}
function Fold(){
if (this._parent.directory_mc._visible){
this._parent.directory_mc._visible = false;
this._parent.directory_mc._yscale = 0;
}else{
this._parent.directory_mc._visible = true;
this._parent.directory_mc._yscale = 100;
}
ArrangeContents(this._parent._parent);
scrollbar.contentChanged();
}

The first two functions, SetAtBottomOfParent and SetBelow are used to position the individual empty directory movie clips and attached item clips (respectively).

function SetAtBottomOfParent(below_mc){
if (below_mc._parent._height) {
below_mc._y = below_mc._parent.getBounds(below_mc._parent).yMax;
}
}
function SetBelow(below_mc, top_mc){
if (top_mc != undefined) {
below_mc._y = top_mc.getBounds(top_mc._parent).yMax;
}
}

Each function vertically positions a passed clip, below_mc, to be either below its _parent or another movie clip through the use of the getBounds method. As you might be able to imagine, SetBelow will be useful with a directory item and its previousSibling property. And what do you know, the next function, ArrangeContents, does exactly that:

function ArrangeContents(directory_mc){
var item = directory_mc.firstChild;
if (item != undefined){
while (item = item.nextSibling){
SetBelow(item, item.previousSibling);
}
var parent_container = directory_mc._parent._parent;
if (parent_container != undefined) ArrangeContents(parent_container);
}
}

ArrangeContents gets passed to it a directory container movie clip. If it has a firstChild, it would mean there are movie clips within it. This would have been assigned in the for loop attaching the clips. Then positioning would be performed, otherwise the function just ends.

To position items, a while loop is used to cycle through each sibling of the movie clips starting with the first in the directory_mc. SetBelow is then used to position that sibling below the sibling before it.

Now, the thing to remember is that if you reposition the contents of a directory, other directories, such as the one containing the directory in question, will have to react and reposition their content as to prevent gaps in the directory layout. ArrangeContents handles this by calling itself (recursively) on the directory_mc's _parent._parent if it exists, ultimately correcting all movie clip positions that the initial change could have effected. (_parent._parent is used since _parent reflects the attached item clip used for the directory and we want the directory clip in which it exists or its _parent clip).

That brings us to the remaining Fold function which is assigned as an onPress event for directories.

function Fold(){
if (this._parent.directory_mc._visible){
this._parent.directory_mc._visible = false;
this._parent.directory_mc._yscale = 0;
}else{
this._parent.directory_mc._visible = true;
this._parent.directory_mc._yscale = 100;
}
ArrangeContents(this._parent._parent);
scrollbar.contentChanged();
}

This shows or hides directory contents. Because this is assigned to a button within an attached item movie clip, _parent is used to access the directory_mc within that item. Then the directory is hidden and set to have a _yscale of 0. The inclusion of the _yscale is necessary because, despite the fact that this movie clip may be invisible, its height would still register as part of its parent's height. This means that hiding the clip alone will not be enough for ArrangeContents to recognize there being a gap. The clip would actually have to be literally folded up. When that happens, ArrangeContents is called and all movie clips get to react to the new change in position, whether it was movie clips being shown or being hidden.


 


kirupa.com's fast and reliable hosting provided by Media Temple. flash components
The Text Animation Component for Flash CS3
Check out the great, high-quality flash extensions. Buy or sell stock flash, video, audio and fonts for as little as 50 cents at FlashDen.
Check out our high quality vector-based design packs! Flash Effect Components
flash menus, buttons and components Digicrafts Components
The best flash components ever! Entheos Flash Website Templates
Upload, publish, deliver. Secure hosting for your professional or academic video, presentations & more. Screencast.com Purchase & Download Flash Components
flash components Free Website | Make a Website
Streamsolutions Content Delivery Networks Learn how to advertise on kirupa.com