You are Here:Home>>Old Posts>>Tutorial | Creating liquid GUIs with Flash and ActionScript 3.0

Tutorial | Creating liquid GUIs with Flash and ActionScript 3.0

By | 2008-04-28T21:24:42+00:00 Apr 28, 2008|Old Posts|


By James O’Reilly

jamesor.com

With user experience expectations on the rise, developers increasingly are looking for ways to bring the rich experience of a desktop application to the web. This article is about developing dynamic graphical user interfaces (GUIs) that mold themselves intelligently to the size of the screen to meet users’ expectations.

A liquid is a collection of molecules that move about each other freely and tend not to separate. In web development circles, “liquid” mostly refers to a web page whose design intuitively moves about freely to fit a web browser window of any width and still looks as the designer intended. This is in contrast to fixed-width web pages, which are designed to fit a predetermined width and normally fill the remaining space, if any, with a solid or tiled background. While all the rage at one point, liquid pages today have mostly been abandoned for fixed-width pages. I can only speculate as to why liquid pages became unfashionable.

Regardless of the demise of liquid web pages, users still expect their desktop applications to have liquid interfaces—and the better ones do. When you open up an application and resize it, you expect that it will repaint itself to accommodate the new size while still providing a usable interface.

To illustrate liquid GUIs, Figure 1 shows two screen captures of the Gaim instant messenger window. You can see how Gaim resizes the GUI controls intelligently to fit the size of the window. Users have grown accustomed to this type of intelligent design in desktop applications. More and more such applications are making their way to the web, increasing user expectations every day. People want rich Internet applications that look and feel like their desktop counterparts.

Gaim instant messenger window shown at two different sizes

Figure 1. Gaim instant messenger window shown at two different sizes.

Sneak peek at the final product

In this tutorial I’ll explore an underutilized property of the Stage object in Flash to create a liquid application interface. In the sample application I am going to create a typical image gallery that you might see on a website—well, maybe not typical because this one will kick ass! This version of the gallery will open up in a new window and behave more like a desktop application.

The gallery will contain three main sections: header, body, and footer. The header will contain the title of the application as well as some buttons for user preferences. The buttons will enable the user to switch back and forth between actual size images and best-fit images. The body will contain the image chosen for viewing by the user. Finally, the footer will contain an array of thumbnail images representing each of the full images available to the user for viewing. So far, this is nothing you haven’t either seen or implemented already.

Example of a non-scaling application inside a resizable window

Figure 2. Example of a non-scaling application inside a resizable window

You’ll notice that this gallery is in a non-resizable window. This is typical for Flash-based pop-up windows because, if the browser window is scaled to a size not respectful of the original aspect ratio, the SWF becomes distorted (see Figure 3).

Example of an application set to match the width and height of a browser window

Figure 3. Example of an application set to match the width and height of a browser window

This version is just unacceptable. The first version might disappoint users who have large monitors because they cannot make the window any bigger than it is. A user with a 1600 x 1200 or larger desktop might be a bit annoyed to see such small images. On the other hand, they would probably be less impressed with a window that scales to any size and distorts the proportions of the graphics.

Now look at Figure 4. This is what I’m talking about! Finally, an application that provides desktop-like behavior as it intelligently scales to accommodate any size browser window. Users will quickly forget that they are using a web-based application as they resize it to fit their needs.

Example of an application which properly scales to fit the browser window

Figure 4. Example of an application which properly scales to fit the browser window

Requirements

In order to make the most of this article, you need the following software and files:

Flash CS3 Professional

Sample files:

Prerequisite knowledge

Understanding of ActionScript 3.0 and its syntax.

Understanding the basics

There are four basic parts to creating a liquid GUI with Flash. In this tutorial, I will create a sample liquid GUI application, going through each of these parts in more detail:

  1. Identify the parts of your GUI that resize and how they do so.
  2. Set the HTML page to display the application at 100%.
  3. Set the Flash movie not to scale its contents automatically.
  4. Add intelligence to the application so that it knows how to scale when the browser window resizes.

Identify the parts of the GUI that resize, and how

My image gallery has three clearly identifiable sections, so identifying the parts that resize is easy. All three sections resize, though not in the same way. The header and footer sections resize only in the horizontal direction, while the body resizes in both directions. As for relocation, only the footer relocates vertically to lock itself to the bottom of the window, while the header and body sections each maintain their original x and y location.

The header section is made up of three children: title, button group, and background image. The background image resizes its width to match that of the window. The title and button group components are unaffected by the resizing.

The body section is made up of two children: an empty movie clip, which acts as a container for the loaded image, and a background fill. The background fill resizes itself to match the width of the window, and the image holder runs a series of calculations to maintain the center of the background fill depending on the size of the image loaded and the actual or best-fit preference chosen by the user.

Finally, the footer section is made up of two children: the group of image thumbnails and a background fill. The background fill resizes itself to match the width of the window, while the thumbnails group is unaffected. (In a real-world application, the thumbnails container might behave like Microsoft Word and display arrow buttons should the window get too small. Since this is a tutorial, I kept the features to a minimum so I wouldn’t stray too far from my focus.)

Set the HTML page to display the application at 100%

The point of the liquid application is to fill the browser window 100% vertically and horizontally so that it takes up the entire window.

To ensure that the application fills the entire browser window, the margin needs to be set to zero. Otherwise, a default width of 10 pixels will surround the application:

Making the SWF fill the browser window is very simple—just a matter of configuring the SWF file’s publish settings.

Open the FLA file in Flash CS3 Professional. Choose File > Publish Settings. Make sure you have the HTML (.html) checkbox checked; then click the HTML tab. Select Percent from the Dimensions drop down list; then enter 100 for both the width and height properties. This setting will make the SWF fill the entire browser window.

The next two publish settings can be done through parameters of the object and embed tag, but it’s not my preference to do so. They are on the same HTML tab:

  1. Select “No scale” from the Scale pop-up menu.
  2. Under Flash Alignment, select Left for horizontal and Top for vertical alignment. This pins the (0,0) coordinates of the Stage to the upper left pixel of the browser window.

My preference for these last two settings is to do it in ActionScript so that the values are used by the player when I test my movie inside of the Flash authoring environment. Otherwise, you can’t properly test your movie.

Set the Flash movie not to scale its contents automatically

To handle the last two settings with ActionScript, I set two of the Stage object’s properties to equivalent values of that found on the HTML settings tab.

The first property is Stage.scaleMode, which I set to noScale, and the second property is Stage.align, which I set to TL.

These four ActionScript lines, accompanied by the object and embed parameters for 100% width and height, are all the settings needed to start writing liquid GUIs.

Add intelligence to the application so that it knows how to scale when the browser window resizes

Using ActionScript to prevent automatic scaling of the SWF means that the SWF will not scale at all; unless, of course, I manually scale every movie clip, which is exactly what I will do.

The remaining portion of this tutorial will take you through the process of building the gallery application. I have broken up the gallery into four progressive versions that add features and complexity to the application.

  • Version 1: I create a bare-bones shell that demonstrates how to listen for resize events and manually scale the movie’s parts accordingly
  • Version 2: I show you how to create a container for your GUI and how to extend the MovieClip class with a custom GUI class that handles resizing
  • Version 3: I show you how to make the app scalable using polymorphism by implementing a custom IResizable interface for all sections
  • Version 4: I briefly talk about the other features in the gallery and how they were implemented

Developing the basics

In this article, we will be developing the application in two ways. The first way will start off as simply as possible, developing directly in Flash CS3 Professional. As the article progresses, I will layer on increased levels of complexity.

Version 1

Using Flash CS3, I start off by creating a movie clip for each of my three sections: header, body and footer. I place each of those clips in separate layers with header the topmost, footer the second, and body the last. I place the body section as the bottom layer so that images loaded larger than the available body size will be clipped by the header and footer sections. These movie clips are each given an instance name by selecting the movie clip while it’s on the Stage and typing a name into the box labeled “<instance name>” in the Properties panel so that I can refer to them from ActionScript. I use the names header_mc, body_mc, and footer_mc, as they clearly identify the sections as well as provide code insight by using the suffix _mc.

On a fourth layer named “Actions” (so named purely for readability), I add the following ActionScript:

In the above code I do a couple of things. First, I make sure that Flash isn’t going to scale the SWF as the browser resizes because I want to handle all resizing with my own code. Second, I make sure the coordinate system remains intact by pinning the Stage to the upper left corner of the movie. (By default, Flash centers the Stage.) Next, I create a listener object that will execute some code every time the Stage is resized. It knows that the Stage is resized because I add it as a listener to the Stage object’s Resize event.

The Resize event can happen many times per second as the user resizes the window. I want to make sure that the event handler runs as efficiently as possible to make the redraws as smooth as possible by keeping the frame rate high. Inside the resizeHandler event handler, I store the Stage object’s width and height as local variables to speed up access to them should I need them often. Because all three of the sections are supposed to match the width of the browser at all times, I simply assign the Stage object’s width to all three sections. I chain them in one long assignment because this executes faster than if it were three separate assignments. Next, I figure out the height of the body section by subtracting the heights of the header and footer sections. Finally, I move the footer section to always be located at the height of the Stage object minus the height of itself, giving it the appearance of being docked to the bottom of the window.

Version 2

Now that I have the easy version out of the way, let me delve into more complex functionality. Version 2 will be identical to Version 1, except it will be built using the new document class. New for ActionScript 3.0 is the ability to create a class that acts as the entry point for your application.

Starting with a new folder for this version, copy your LiquidGUI_v1.fla into it and rename it as LiquidGUI_v2.fla. Open the FLA in Flash for editing. Delete all the content on the Stage and any layers you may have created; they won’t be needed. In the library, set the class for each of the three movie clips to HeaderBG, BodyBG, and FooterBG, respectively. Set the base case for each to flash.display.Sprite (see Figure 5). By default, it will be MovieClip, but since we don’t need the Timeline, we’ll use Sprite. The linkage identifier will be grayed out because it is not available when publishing to Adobe Flash Player 9 with ActionScript 3.0.

Setting the class and base class

Figure 5. Setting the class and base class for each of your symbols

At this point, your FLA should just be three movie clips in the library and nothing on the Stage. Publish the FLA to a SWF file that’s compatible with Flash Player 9 and ActionScript 3.0 (see Figure 6), and leave the SWF file in the assets subfolder.

Publish Settings dialog box

Figure 6. Flash Player 9 and ActionScript 3.0 compatibility settings in the Publish Settings dialog box

There are two ways to define the document class of your application. One way is by clicking on the Settings button in the Publish dialog box. The other is by using the Properties panel; enter LiquidGUI_v2 in the Document Class text box and click the pencil icon to the right of it (see Figure 7).

Defining the document class as LiquidGUI_v2

Figure 7. Defining the document class as LiquidGUI_v2

Using the File menu, create a new ActionScript file named LiquidGUI_v2.as in the same folder as your FLA. This class will extend the Sprite class to inherit its functionality. Open the class for editing and enter the following code:

Most of the code should look familiar; it was taken directly from Version 1. The main class and starting point for our application is the LiquidGUI_v2.as class.

Inside the class, I define some constants that I use throughout the lifespan of the application. These values never change, so I create them as static variables to improve performance over accessing the necessary properties of objects to get the same answer.

In my example, I don’t want to use a timeline, so I type my objects as Sprite like this:

After creating a Sprite instance of the FooterBG class, you must add it to the display list for it to be seen. To do that, you would use the addChild() method of the container to which you wish to add the Sprite:

Finally, implement a public method named onResize which accepts an event object as a parameter.

Adding to the application

The first two versions were simple implementations to illustrate the basics. Now that I’ve shown you the foundation for handling application resizing, I’ll continue to build upon the application. If you haven’t done so already, please start with developing the first version, as the four versions are progressive.

Version 3

In Version 3, I start with a new project named LiquidGUI_v3; but feel free to continue on with Version 2 if you prefer. In Version 3, I dumb down the main class, as it really does not need to know how to implement the resizing of its children. Instead, the class will limit its capabilities to relocating children to proper locations and telling children what size to resize themselves. The first part remains the same, as the main class simply sets x and y locations of any children that need to move. In this case, the only Sprite moving is _footer in the vertical direction, so it continues to set _footer.y. Resizing is handled differently, however.

The first thing to do is create a series of folders that will hold your custom classes. The folders define the package (namespace) in which the classes live, so they need to be exact. Packages are used to avoid naming conflicts between classes of the same name. If you and I were to create two classes named CustomButton, we would have a problem using them in the same project unless they were located in separate packages. Because classes must have a filename that’s the same as the class name (plus the .as extension), you will not be able to put two classes with the same name into the same folder anyway, which helps with preemptive conflict resolution.

The package structure I always use is “com.jor”. Short for commercial, “com” is the standard base namespace, so I start with that. Inside the folder “com” I create the folder “jor”—short for, as you might have guessed, James O’Reilly. From there I create a series of different folders for different things. For this project I use two specific folders: “controls,” which you will see much later, and “examples”. Inside “examples” I create a folder for this project called “liquidgui”. Inside liquidgui I create a folder called “ui”. The final directory structure for your project, including project-created folders, should look like this:

Next, create new classes that extend Sprite for each of our three components. Those files should be:

Since each component can potentially act as a container and contain children components that, in turn, may contain children components (and so on), it makes more sense to let the child handle its own resizing by just telling it what size it is supposed to be. Each component we create is going to be its own custom class, so we will use polymorphism and call the same method setSize() on all clips that need resizing. To do this, we need to create an interface that will be implemented by all classes that resize themselves. In the liquidgui folder, create a file named IResizable.as, open it for editing in Flash, and add the following code:

Creating an interface is easier than creating a class because there is no code. An interface simply defines the methods that need to be present in the class that implements it. Here you see that you require a method named resizeTo that returns void and accepts two parameters, each a number. The line ends with a semicolon, and there are no curly braces such as the implemented method will have. All interfaces need to be defined as public, because interfaces are what you use to expose your class to the outside world.

You will use this interface with each of the new classes. Open HeaderUI.as for editing and add the following code:

This is the code for the HeaderUI class. In the first few lines, you can see it extends the Sprite class and implements the IResizable interface. Inside the class there is a reference to the bg movie clip so it can access it. Then you see its required implementation of the setSize() method. For this class, the only thing it does when it resizes is set bg.width to the width passed in as w.

The other two classes, BodyUI and FooterUI, appear below and should look very similar to HeaderUI:

Finally, you need to update the main class to make use of these new method calls instead of handling the resizing internally. Here’s the newly implemented onResize method of the main class along with the instantiation of the three new component classes:

Version 4

I add a lot more functionality in this final version of the gallery application.

Because this functionality becomes complex and veers from the topic of creating a liquid GUI, I’ll just go over the main points and let you explore the source code in more detail:

  • Header section: I add a series of radio buttons so that the user can toggle between an actual size state and a scaled size state. The buttons are created as custom radio buttons. When a button is clicked, a custom onChangeState event is dispatched that passes an event object containing the name of the state to which to change.
  • Body section: In this section, I add a loader object into which to load the images. The class BodyUI also uses the State pattern to toggle back and forth between states. By creating a concrete implementation of actual-size behavior and separate concrete implementation of a scaled-size behavior, I could change the state of the BodyUI class at runtime by simply assigning one state or another to the current state. Explaining the State pattern in depth deserves its own tutorial, so please review the source code to see how this was done and check out the Head First: Design Patterns by Eric Freeman, Elisabeth Freeman, Kathy Sierra, and Bert Bates (O’Reilly Media, 2004). The BodyUI class also implements an Event listener and listens to events dispatched by both the header and footer.
  • Footer section: In this section, I implement a simple loader to display thumbnail images one after another. Each thumbnail image is a new instance of a ThumbnailUI class which implements mouse click event handling. When a thumbnail is clicked, a custom event is dispatched that passes an event object containing the path of the image to load.

Where to go from here

I hope you found this tutorial fun and informative. The gallery application is a nice start for something that can really be embellished. Here is a short list of things you can do to improve upon this example:

  • Design your own custom interface
  • Have the footer load in an image list from an external source such as XML
  • Include metadata in the XML to appear alongside the image, such as name, file size, and description
  • Add scroll bars to the body section that appear only when the image loaded is larger than the body’s area
  • Add scrolling action to the thumbnail images when the window size doesn’t enable all the thumbnails to appear, or perhaps resize the thumbnails to fit
  • Add a gallery chooser so that the user can switch between galleries within the same application
  • Build something completely different using the same approach, such as an RSS news reader
  • Share your creations and embellishments with me and others so we can all learn new things!

Lastly, I always like hearing from people. Feel free to contact me with any questions or suggestions you might have. The best place to contact me is at my active blog, jamesor.com. Happy coding!

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

About the author

James O’Reilly, an Adobe Certified Expert, is the CTO of SynergyMedia, Inc., a New York–based Flash consulting and training company. His blog, jamesor.com, is his collection of thoughts and ideas around Flash and Flex development. Aside from coding, James enjoys playing darts competitively and cruisin’ with the top down.
This Tutorial was originally posted at Adobe.com.

About the Author:

A father, a husband and a geek... Carlos was the founder of projects like The Tech Labs and Flash Enabled Blog. He is the founder of TekTuts He is passionate about technologies. Their main skills are in analytics, transport & logistics, business administration. He also writes about programming resources, trends, strategy and web development.

One Comment

  1. Tom December 2, 2008 at 4:22 am - Reply

    James,
    I installed CS4 two days ago and am still getting used to it. I used to have CS2, so I am fumbling through the non-documentation of the AS3 methods and metaphors.
    Concerning the resizing of components, I created a rectangle and converted it to a movieclip. Double clicked on that, placed a text field inside of that.
    Two questions:
    1) When I resize the movieclip, the text box autoresizes to be larger than the movie clip and overflows the boundaries of the movieclip. Is this a bug?
    2) How do I prevent the text box from resizing at all. I don’t want the text to be huge, I just want more text to be displayed within the text box.
    Thanks.

Leave a Reply