Full Browser Flash
Using Flash CS4 and ActionScript 3 to dynamically reconfigure layout
Let's face facts, folks: sometimes just scaling your entire Flash movie to an arbitrary window size won't cut it. A prime example of one of those times would be if you're using Flash to create Web-based applications, where your users would rightfully expect to have the application interface scale intelligently to the size of their browser window. Flex Builder can do this through a simple GUI panel, but the process is a little more involved if you're using Flash CS4 Professional, which is where we'll pick things up.
The setup
We're not going to get too terribly complicated with this; the whole idea is that by keeping things simple, you can quickly jump off into your own experiments from here. With that in mind, let's set up the Flash movie and create the host HTML page.
Fire up Flash CS4 and create a new ActionScript 3-based Flash file. Unless you've changed the default profile, you'll get a 550x400 movie with a white background, which we'll leave the way it is. Don't worry if you have a different background color and stage size specified -- pretty much anything will do for this tutorial. Go ahead and save the file.
Once the file is saved, head to the Publish Settings panel (File: Publish Settings). Make sure the Flash and HTML options are checked in the Formats tab, then click on the HTML tab and set the Width and Height to 100%, the Scale to No scale, and the Flash alignment to Left and Top. Figure 1 shows you what your panel should look like before clicking OK.

Figure 1
Go ahead and publish the movie (File: Publish), which will generate the (currently blank) SWF file and the HTML. We need to take care of a small nit in the automatically generated HTML at this point, so using your favorite text editor (or some other application that allows you to edit raw HTML code), open up the HTML file. Right below the
<style type="text/css"> body {margin:0; padding:0} </style>
This little bit of CSS will prevent the scrollbar from showing up, which we don't need anyway, as the whole point of this exercise is to have the Flash movie scale to whatever size the browser window is. Save the HTML file, switch back to Flash, open the Publish Settings panel again, and uncheck HTML in the Formats tab. We don't need Flash overwriting our now-changed HTML every time we publish, so with that set, hit OK to return to the Flash stage.
The assets
We're going to need to create a couple of things in the Library. For one, we'll need a rounded rectangle, because in addition to being useful in seeing how our interface scales to the window size, rounded corners on rectangles are way cool. In Flash, open the Library panel if it isn't already (Window: Library) and click the New Symbol icon at the bottom left of the window. The Create New Symbol dialog will open up. Enter in the following settings:
- Name: mcRoundedRect
- Type: Movie Clip
- Click the Advanced button and check the "Enable guides for 9-slice scaling" box
Click OK to create the symbol and enter the symbol editor. Select the Rectangle Primitive tool from the Tool panel and draw out a 50x50 rectangle onto the Stage. The color can be whatever you want (mine is a darkish gray with no stroke applied), but make sure the registration point is set to the top left (in other words, XY coordinates of 0,0). Then, using the Properties panel, give it a nice uniform 10 pixel curve in the Rectangle Options section. The panel should look something like Figure 2:

Figure 2
Your rectangle should look similar to Figure 3, with the 9-slice scaling guides nice and evenly distributed. Again, note the registration point (the crosshairs) at the top left:

Figure 3
Let's create another rectangle, this time of the non-rounded variety and with a gradient fill. Create another new Movie Clip symbol in the library and name it mcBG (no 9-slice scaling necessary on this one). In the symbol editor, draw out a 50x50 square (again with the registration point set to the top left) using either the regular Rectangle tool or the Rectangle Primitive tool (I prefer the latter, for whatever that is worth). In either case, make sure there is no stroke applied and the fill is set to whatever gradient makes you a happy camper. Just for kicks, my oh-so-exciting symbol is shown in all its glory in Figure 4:

Figure 4: Behold -- the greatest screenshot in the history of mankind.
The Layers
OK, we've got our rounded rectangle set, we've got our background set, so let's put 'em into some layers. Head to the Timeline (Window: Timeline if it's not already open) and click the New Layer button twice to add two additional layers. Name the bottom one bg, the middle one rects, and the top one actions. Your Timeline should look something like Figure 5:

Figure 5
Let's add the background layer first. Select frame 1 of the bg layer and then drag an instance of the mcBG symbol from the Library to the Stage. Use the Free Transform tool to position and size the instance to the overall size of the Stage. Finally, using the Properties panel, set the name of this instance to bg_mc.
Now for the rounded rectangles, which will simulate interface panels. Select frame 1 of the rects layer, then drag two instances of the mcRoundedRect symbol from the Library onto the Stage. Scale and position them so you have one on the left that is narrower than the one on the right, then name them left_mc and right_mc, respectively, in the Properties panel. Once that's done, your Stage should look roughly like Figure 6:

Figure 6
If you want your panels to look exactly like mine, use the following specs:
left_mc:
x: 20
y: 20
width: 150
height: 360
right_mc:
x: 190
y: 20
width: 340
height: 360
These specs assume that you left the default Stage size alone (550 x 400), which will give you a nice 20 pixel gutter on all sides around each panel. Once you've done all this, you should still have one empty layer left in the Timeline -- the actions layer -- which we'll start to fill up with code presently.
The Code
The end result we're shooting for is for the left panel to keep a static width of 150 pixels but resize its height to stay 20 pixels from the bottom of the browser window at all times. The right panel needs to adjust both its width and height to maintain the same gutters, and the background needs to scale to 100% of the height and width of the browser window at all times. What all that ultimately means is that we need to write a function that can calculate these values, and add a listener which will call that function when the browser window resizes. Fortunately, ActionScript 3 can do this, which is good, because that means I haven't completely wasted your time yet.
Go ahead and click on frame 1 of the actions layer in the Timeline, and then open the Actions panel (Window: Actions) if it's not already open. Here's the code to write in the Actions panel in its entirety, which we'll break down immediately thereafter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | stop(); stage.addEventListener(Event.RESIZE, wResize); function wResize(e:Event):void { windowResize(); } function windowResize():void { var sw:Number = stage.stageWidth; var sh:Number = stage.stageHeight; bg_mc.width = sw; bg_mc.height = sh; left_mc.height = sh - 40; right_mc.width = sw - 210; right_mc.height = left_mc.height; } windowResize(); |
Let's go through the code step-by-step:
Stop
1 | stop(); |
This is optional, but I always like to put a stop call first thing. Ignore if you like.
The listener
3 | stage.addEventListener(Event.RESIZE, wResize); |
A simplistic but helpful philosophy is to think of ActionScript 3 as cramming everything into the event/listener model, meaning that you get things done by attaching listeners to objects, which then call events when certain criteria are met. In our case, we're attaching a resize listener to the Stage, which calls the wResize function when it "hears" that the Stage has been resized. In a browser environment, adjusting the size of the browser window causes the resize event to trigger.
Responding to the listener
5 6 7 | function wResize(e:Event):void { windowResize(); } |
In ActionScript 3, you have to tell functions what type of event (if any) they are bound to, which necessitates a couple of things in this case. The wResize function shown here is nothing more than a stub function, created only to listen for the resize event (hence the e:Event argument). What it calls, in turn, is a generic function, windowResize, which exists on its own so that it can be used in more than one situation.
The main function
9 10 11 12 13 14 15 16 17 | function windowResize():void { var sw:Number = stage.stageWidth; var sh:Number = stage.stageHeight; bg_mc.width = sw; bg_mc.height = sh; left_mc.height = sh - 40; right_mc.width = sw - 210; right_mc.height = left_mc.height; } |
Here's where the heavy lifting, such as it is, happens. The three things we want (fixed width/variable height left panel, right panel that fits the remaining space, and background scaling to the entire window) all get done in the seven lines of code contained in the windowResize function. Lines 10 and 11 simply find the width and height of the stage using the stage.stageWidth and stage.stageHeight properties and assigns them to the sw and sh variables, respectively. Lines 12 and 13 use those variables to set the width and height properties of the background instance. Next, since we are keeping the width of the left panel constrained to a constant 150 pixels, all we need to do on the line 14 is adjust the height of the left panel to the height of the stage minus 40 pixels, thereby keeping that 20 pixel gutter at the top and bottom. Line 15 calculates the width of the right panel by taking the overall stage width (the sw variable) and subtracting 210 pixels (the 150 pixel width of the left panel plus 60 pixels, or the width of the left, right and middle 20 pixel gutters).
(As an aside, since the registration point of both panels is set to the top left, we don't need to set the x or y coordinates in either case, though it wouldn't be terribly difficult to calculate those coordinates based on the values of sw and sh if the situation called for values that were based more on percentages rather than fixed coordinates like we have here.)
Lastly, line 16 simply sets the height of the right panel to the height of the left panel, which was calculated earlier.
Calling the function
19 | windowResize(); |
Remember a few paragraphs back when I mentioned that windowResize "exists on its own so that it can be used in more than one situation?" This is that other situation. When the movie first loads in a browser, there won't be any resize event to respond to, so we need to call windowResize right off the bat so that the panels will align themselves to whatever the browser window size happens to be when the movie is loaded.
...And the result
So, now that we've gotten the code written and, more importantly, understood, publish the movie one last time. Then, open up the HTML file we fiddled with earlier in your favorite browser. If all went as planned, you should be able to resize the browser window to your heart's content, and the movie should behave similarly to what you see in Figure 7:
Figure 7
As you can see, our gradient background is always the size of the browser window, the left panel stays 150 pixels wide while keeping a consistent 20 pixel gutter at the bottom, and the right panel scales both horizontally and vertically to maintain its relative size. Plus, since we set up 9-slice scaling on our rounded rectangle, there is always a consistent 10-pixel curve at the corners of each panel. Pretty nice, huh?
Taking it further
Again, this is an admittedly simple example, but hopefully one which serves as a good jumping off point for projects that call for dynamic interface layouts. With a little bit of math, you can have dynamically expanding, contracting, and even scaling interface elements, providing a more application-like interface for your users. We Flash Pro users may have to do a little more work than our Flash/Flex Builder-using compatriots in order to dynamically lay out interfaces, but once you've done this on your first project, the knowledge carries over into a wide variety of situations.
Got Feedback? to send an email. I'll do my best to answer. Really.
