Custom Move and Resize Window Controls in AIR

WARNING: This was written for a BETA version of AIR and may not be valid for the most recent release

One of the advantages of AIR is having complete programmatic control over application windows. This means you can create and modify windows on the fly through JavaScript or ActionScript. This tutorial will cover how you can use ActionScript to both move and resize an AIR application's window using Flash controls.

Requirements:

Note: Though this tutorial uses Flash CS3, the same ActionScript could be applied to an AIR project in Flex Builder.

Source files:

An AIR Application's Window in ActionScript

When an AIR application runs, it defines in an application's stage instance a property called window which relates to the window containing that application. The window property is an instance of the NativeWindow class (flash.display.NativeWindow).

The NativeWindow class contains a number of properties and methods that relate to the window that is containing the application. These include properties like x and y for changing the location of the window as well as width and height for adjusting its size. In addition to those properties, the NativeWindow class also includes two methods for invoking native window movement and resizing, startMove() and startResize(). When called, these methods will allow a user to move their mouse to naturally control the window's location or size without any extra effort on the developer's part. These are the methods that will be covered with the example in this tutorial.

The Move and Resize Application

  1. Open windowMoveAndResize.fla from the source files

This application consists of 5 buttons. Each either move (center) or resize (corners) the application window when this application is run in AIR.

  1. Select the first frame of the actions layer
  2. If not already open, open the Actions panel using F9 or Window > Actions to show the ActionScript code for this application

The code is divided into two parts. The first covers the interaction with the buttons for moving and resizing the application window with the buttons. The second handles the repositioning of those buttons as the window changes size.

Moving and Resizing

Could letting a user move a window through a Flash control in your AIR application be any easier, you ask? No, it couldn't. As long as you have access to the stage (which any display object on the active display list does), you can easily move a window in Flash by calling startMove() from stage.window. In this example, that action is called in the moveWindow() handler for the moveButton's MOUSE_DOWN event.

moveButton.addEventListener(MouseEvent.MOUSE_DOWN, moveWindow);
function moveWindow(event:MouseEvent):void {
	stage.window.startMove();
}

Resizing is very similar except the startResize() method includes a single argument that allows you to specify which edge or corner of the window you want to resize from. Each of the four corner buttons in the application each resize the application window using a different corner so each of them will need to call startResize() with a different value.

The values accepted by are included within the NativeWindowResize class (flash.display.NativeWindowResize). They consist of:

The resize buttons in this example only use the corners, so TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, and BOTTOM_RIGHT will be used. Though each button could have its own event handler calling startResize() with the respective value, a single handler is used and the appropriate corner is assigned in a switch statement based on which button was pressed.

resizeTLButton.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
resizeTRButton.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
resizeBRButton.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
resizeBLButton.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);

function resizeWindow(event:MouseEvent):void {
	var corner:String;
	switch(event.currentTarget){
		case resizeTLButton:
			corner = NativeWindowResize.TOP_LEFT;
			break;
		case resizeTRButton:
			corner = NativeWindowResize.TOP_RIGHT;
			break;
		case resizeBRButton:
			corner = NativeWindowResize.BOTTOM_RIGHT;
			break;
		case resizeBLButton:
			corner = NativeWindowResize.BOTTOM_LEFT;
			break;
	}
	stage.window.startResize(corner);
}

Fitting Content to the Stage

The default behavior for a Flash SWF when its container (such as the AIR player) changes size, is to fit itself within the new container size as best it can without distorting the contents of the SWF. This, however, can lead to bars either above and below or to the left and right of the SWF possibly showing content that would otherwise not be seen.

Extra effort needs to be taken to make an application that will intelligently scale within an adjustable container. Flex has the advantage of being built on a component infrastructure that does this automatically. Flash users will have to put a little more effort into this. For our buttons here, however, not much work is needed.

The first step is to set up the behavior of the way the Flash Player stage resizes so that all content is positioned based on the upper left and does not scale with the container as the container changes in size.

stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;

Next, an event handler is created for the stage's RESIZE event which is used to position the necessary elements on the screen in their respective positions. Here, its just a matter of making sure all the resize buttons stay in their corners and the move button stays centered.

stage.addEventListener(Event.RESIZE, updateGUI);
function updateGUI(event:Event):void {
	moveButton.x = stage.stageWidth/2;
	moveButton.y = stage.stageHeight/2;
	resizeTRButton.x = stage.stageWidth - cornerOffset;
	resizeBLButton.y = stage.stageHeight - cornerOffset;
	resizeBRButton.x = resizeTRButton.x;
	resizeBRButton.y = resizeBLButton.y;
}

Now, whenever the size of the stage changes, the updateGUI() event handler will be called and properly position the resize and move buttons as needed.

Note that there is a new resize method specific to AIR, NativeWindowBoundsEvent.RESIZE (flash.events.NativeWindowBoundsEvent) . This event, however, is specific to the window resize within the context of the operating system. It does not relate to content being drawn within the AIR Flash player. When you want to update objects on the screen, you would use the stage's RESIZE event, not the RESIZE event of NativeWindowBoundsEvent.

If you test this movie in Flash, you can see how the buttons can be used to change the window position size and how they position themselves as expected within that window as the window size changes.

Conclusion

This example showed how you can make Flash-based controls perform operating system-based tasks. In this particular example, the controls changed window size and position. These operations, though, were redundant since the window containing the application already provided those capabilities - and even more. Where you would really use these features are in windows without any window chrome. Then, you users will be without the default window border and title bar and would need to rely on your controls for any kind of window manipulation.

Moving forward you will want to look into the other NativeWindow events. The RESIZING event (not to be confused with RESIZE), for example, is a cancelable event that will let you set limits as to how big or small a window can be resized. This could be especially important when dealing with interfaces that break down once they get too small or two big. Having control over how your application's window is used can be a key factor in making sure it continues to run smoothly and in an attractive manner.