Flash Liquid Layout Dynamic Positioning

Following another post regarding using stage listeners to dynamically resize and position MovieClips in Flash, I was asked to upload and FLA as an example. The previous code can just be pasted into the actions panel and will run without any MovieClips needed, and was designed to show the StageListener function rather than showcase a particular dynamic layout.

Download: Fluid Flash Layout Example

Anyway, here is a slightly amended version of this simple technique which uses MovieClips, and produces a fluid layout based on percentages (much like the classic CSS three column layout).

Again, this can be easily modified to include more elements, margins etc. Note – if you want to add content to the Movieclips (for example A menu in the left column), simply make the resizable elements a background MovieClip inside each parent MovieClip.

For instance, our left column would then be resized by using:

leftCol.backGround.pos(x, y, w, h);

The content inside the leftCol MovieClip would then maintain its size as the background resizes. Easy.

// Setup the Stage properties
Stage.scaleMode = "noScale";
Stage.align = "TL";

// Variables (in pixels)
var headHeight:Number = 100;
var footHeight:Number = 50;

// Variables (in percent)
var leftColWidth:Number = 25;
var mainColWidth:Number = 60;
var rightColWidth:Number = 15;

// Prototype function to position MovieClips
MovieClip.prototype.pos = function (x, y, w, h)
{
	this._x = x;
	this._y = y;
	this._width = w;
	this._height = h;
};

// Out main function
function setStage ()
{
	var sw:Number = Stage.width;
	var sh:Number = Stage.height;
	// Calculate percentages based on Stage dimensions
	var Lw:Number = sw / 100 * leftColWidth;
	var Mw:Number = sw / 100 * mainColWidth;
	var Rw:Number = sw / 100 * rightColWidth;
	var Hp:Number = sh - (headHeight + footHeight);
	// Position / resize our MovieClips
	header.pos (0,0,sw,headHeight);
	leftCol.pos (0,headHeight,Lw,Hp);
	mainCol.pos (Lw,headHeight,Mw,Hp);
	rightCol.pos (Lw + Mw,headHeight,Rw,Hp);
	footer.pos (0,sh - footHeight,sw,footHeight);
}

// Add a listener
var stageListener:Object = new Object ();
Stage.addListener (stageListener);

// When the Stage dimensions change...
stageListener.onResize = setStage;

// Call our function to set it all up right!
setStage ();
Posted on 08 Mar 2007
Posted in
Tagged
57 Comments
0 Trackbacks

Meta

Dynamic Positioning Continued was posted on March 8th 2007 in the category Code / Code, Flash and tagged; , , .

You can Leave a comment.

Twitter <follow>

February 7th 2012 - 5:37pm

RT @_leonardsouza_: 37signals to stop developing for IE8 » http://t.co/wL6dtZSg

Discussion

57 Responses to Dynamic Positioning Continued

Leave a Reply

  1. Soulwire 3 years ago

    Hi Arthur,

    To resize an image and retain the correct ratio, you can use this function. The image will be cropped if the proportions of the browser are extreme, but the image will not distort.

    Hope this helps.

    Stage.scaleMode = "noScale";
    Stage.align = "TL";
    
    var ratio:Number = pic._width/pic._height;
    
    function setStage ()
    {
    	var sw:Number = Stage.width;
    	var sh:Number = Stage.height;
    	var sRatio:Number = sw/sh;
    	sRatio>=ratio ? (pic._width=sw, pic._height=sw/ratio) : (pic._height=sh, pic._width=sh*ratio);
    }
    
    var stageListener:Object = new Object();
    Stage.addListener (stageListener);
    
    stageListener.onResize = setStage;
    setStage ();
    

    Reply to this comment

  2. Wahiche 3 years ago

    I have to say thank you for this script is is fantastic. I have been looking for something like this for a long time. I am not a very talented actionscripter as my skills lie mainly in the design side, and I am not too great at that either…lol. Just being hard on myself.

    But I do have a question regarding the code here. I have added more code to it to change the layout and to add an image in one of the containers. All my code works fine as it seems but I find that when I compile it that the image does not scale properly until I resize the stage. Can you help please?

    I have attached my version of your code so you can see what I have done.

    Thanks again for being a genius.

    // Setup the Stage properties
    Stage.scaleMode = "noScale";
    Stage.align = "TL";
    // Variables (in percents)
    var headHeight:Number = 20;
    var leftColWidth:Number = 50;
    var rightColWidth:Number = 50;
    var aboveFoot:Number = 15;
    var footHeight:Number = 15;
    // Prototype function to position MovieClips
    
    MovieClip.prototype.pos = function (x, y, w, h)
    {
    	this._x = x;
    	this._y = y;
    	this._width = w;
    	this._height = h;
    };
    // Out main function
    function setStage ()
    {
    	var sw:Number = Stage.width;
    	var sh:Number = Stage.height;
    	// Calculate percentages based on Stage dimensions
    	var HeadH:Number = sh / 100 * headHeight;
    	var Lw:Number = sw / 100 * leftColWidth;
    	var Rw:Number = sw / 100 * rightColWidth;
    	var AFoot:Number = sh / 100 * aboveFoot;
    	var FootH:Number = sh / 100 * footHeight;
    	var Hp:Number = sh - (HeadH + FootH + AFoot);// Height of Middle area
    	// Position / resize our MovieClips
    	header.pos (0,0,sw,HeadH);
    	leftCol.pos (0,HeadH,Lw,Hp);
    	rightCol.pos (Lw,HeadH,Rw,Hp);
    	abovefoot.pos (0,sh - FootH - AFoot,sw,AFoot);
    	footer.pos (0,sh - FootH,sw,FootH);
    
    }
    // Add a listener
    var stageListener:Object = new Object ();
    Stage.addListener (stageListener);
    // When the Stage dimensions change...
    stageListener.onResize = setStage;
    // Call our function to set it all up right!
    setStage ();
    addPic ();
    
    function addPic ()
    {
    	var mcl:MovieClipLoader = new MovieClipLoader ();// you first create a MovieClipLoader object
    	var picListener:Object = new Object ();// and a listener to control the loading...
    	mcl.addListener (picListener);
    	// connect the listener to the mcl...
    	mcl.loadClip ("bg_mlb_tile.gif",leftCol);
    	// parameter 1: file to be loaded
    	// parameter 2: the mc
    	picListener.onLoadInit = function (mc:MovieClip)
    	{
    /* mc here represents the movie clip in which we're
    loading the content, and onLoadInit event handler
    executes as soon as the file is loaded.
    the important thing in here is that you need the
    data be loaded totally before processing the mc.
    */
    		mc._width = leftColWidth;
    		mc._height = Hp;
    	};
    }

    Reply to this comment

  3. Soulwire 3 years ago

    Hi Wahiche.

    Thanks for your comment.

    Have you tried calling the setStage method from inside the onLoadInit function? Currently in your code there is a call to setStage before the pic is loaded, so this function won’t fire again until the stage is resized, as you’ve been observing.

    Also, inside onLoadInit you set the width and height of the movieClip containing the image, but if you want this to resize with the stage you should move this to the setStage function and then call from , if that makes sense?

    Like so:

     function setStage ()
    {
    	// Your previous code here
    	mc._width = leftColWidth;
    	mc._height = Hp;
    }
    /* ... */
    function addPic ()
    {
    	var mcl:MovieClipLoader = new MovieClipLoader ();
    	var picListener:Object = new Object ();
    	mcl.addListener (picListener);
    	mcl.loadClip ("bg_mlb_tile.gif",leftCol);
    
    	picListener.onLoadInit = function (mc:MovieClip)
    	{
    		setStage();
    	};
    } 

    Hope that helps :)

    Reply to this comment

  4. Wahiche 3 years ago

    Thank you for your prompt response but I think what i am trying to do is a little more complicated and if I explained it you may have another suggestion.

    I am trying to make it so that the image gets resized dependant on the width constraint of the container it is in (leftCol). There is a max of 50% of the stage for the width, now I want it to resize the image with the proper aspect ratio.

    this is my new code after a lot of reworking, so I hope that it is understandable. I have made some of the Variables global as I needed to be able to call them in and out of Functions. I also have it set now to resize but it just resizes at some points at the right aspect ratio but does not work properly. I also have a question about the mc that is being created to hold the image. If you do a trace on the mc._width and mc._height you will see that any image in there is always said to have the dimensions multiplied 4:3, why?

    Thank you for all your help and not sure if you ever go on MSN to talk to people about this but if you do i would be glad to have a conversation with you about it. I think you are a genius and would just really like to pick your brain.

    Wahiche

    // Setup the Stage properties
    Stage.scaleMode = "noScale";
    Stage.align = "TL";
    // Variables (in percents)
    _global.headHeight = 20;
    _global.MainRowHeight = 50;
    _global.leftColWidth = 50;
    _global.rightColWidth = 50;
    _global.aboveFoot = 15;
    _global.footHeight = 15;
    _global.myMovie = undefined;
    // Prototype function to position MovieClips
    
    MovieClip.prototype.pos = function(x, y, w, h) {
    	this._x = x;
    	this._y = y;
    	this._width = w;
    	this._height = h;
    };
    
    // Our main function
    function setStage() {
    	_global.sw = Stage.width;
    	_global.sh = Stage.height;
    	// Calculate percentages based on Stage dimensions
    	_global.HeadH = sh/100*headHeight;
    	_global.Lw = sw/100*leftColWidth;
    	_global.Rw = sw/100*rightColWidth;
    	_global.AFoot = sh/100*aboveFoot;
    	_global.FootH = sh/100*footHeight;
    	_global.Hp = sh-(HeadH+FootH+AFoot);// Height of Middle area
    	// Position / resize our MovieClips
    	header.pos(0,0,sw,HeadH);
    	leftCol.pos(0,HeadH,Lw,Hp);
    	rightCol.pos(Lw,HeadH,Rw,Hp);
    	abovefoot.pos(0,sh-FootH-AFoot,sw,AFoot);
    	footer.pos(0,sh-FootH,sw,FootH);
    	imageResize();
    }
    // Add a listener
    var stageListener:Object = new Object();
    Stage.addListener(stageListener);
    // When the Stage dimensions change...
    stageListener.onResize = setStage;
    // Call our function to set it all up right!
    addPic();
    setStage();
    
    function addPic() {
    	var mcl:MovieClipLoader = new MovieClipLoader();// you first create a MovieClipLoader object
    	var picListener:Object = new Object();// and a listener to control the loading...
    	mcl.addListener(picListener);
    	// connect the listener to the mcl...
    	mcl.loadClip("bg_mlb_tile.gif",leftCol);
    	// parameter 1: file to be loaded
    	// parameter 2: the mc
    	picListener.onLoadInit = function(mc:MovieClip) {
    		/* mc here represents the movie clip in which we're
    		loading the content, and onLoadInit event handler
    		executes as soon as the file is loaded.
    		the important thing in here is that you need the
    		data be loaded totally before processing the mc.
    		*/
    		myMovie = mc;
    		var AspectRatioW:Number = mc._width/mc._height;
    		var AspectRatioH:Number = mc._height/mc._width;
    		_global._scaleX = 100;
    		_global._scaleY = 100;
    		_global._scale = 100;
    		_scaleX = Lw/mc._width*100;
    		_scaleY = Hp/mc._height*100;
    		var _scale:Number = Math.min(_scaleX, _scaleY);
    		setStage();
    	};
    
    }
    
    function imageResize() {
    	if (myMovie._width>=Lw) {
    		myMovie._xscale = scale;
    		myMovie._yscale = scale;
    	} else {
    		myMovie._xscale = scale;
    		myMovie._yscale = 100;
    	}
    
    }

    Reply to this comment

  5. Rob 3 years ago

    First of all, love the script; had it working great in AS2 with no problems, but now I’m working in AS3 and haven’t got it to work, don’t suppose you have an AS3 version?

    Thanks.

    Reply to this comment

  6. Soulwire 3 years ago

    Hi Rob,

    No worries! I’ve ported the download above to AS3 for you, enjoy…

    http://blog.soulwire.co.uk/uploads/2007/03/stage-listeners-as3.zip

    Reply to this comment

  7. Rob 3 years ago

    Thanks, that’s awsome!

    Reply to this comment

  8. Ben 3 years ago

    Hey,

    Thanks for a great tutorial. I’ve been playing about with liquid layouts (still using AS2), and I’ve got a quick question. I’ve got a movie clip that floats to the right of the browser window, so as the browser is made smaller the movie clip moves in with it. This is fine, but what I want to achieve is when the movie clip reaches a certain position (the browser window gets too small), it stops floating and becomes fixed. I’ve used the following code:

     [
    
    Stage.align = "TL";
    
    Stage.scaleMode = "noScale";
    stop ();
    
    bottomstretch._height = Stage.height;
    rightstretch._height = Stage.height;
    topstretch._width = Stage.width;
    
    mclogo._x = Stage.width - mclogo._width;
    sizeListener = new Object();
    sizeListener.onResize = function() {
    topstretch._width = Stage.width;
    bottomstretch._height = Stage.height;
    rightstretch._height = Stage.height;
    
    if(mclogo._x >= 738){
    	mclogo._x = Stage.width - mclogo._width;
    }
    else mclogo._x = 738;
    };
     ] 

    While this kind of works, once the browser becomes too small the movie clip constantly jumps from floating to the position I want it. Any ideas? I’m fairly new to AS so any help is greatly appreciated.

    Cheers.

    Reply to this comment

  9. Soulwire 3 years ago

    Hi Ben,

    Have you tried something like:

    // The size at which to stop floating the logo
    var minWidth:Number = 200;
    // Where to fix the logo when not floating
    var fixPoint:Number = 150;
    // Inside your onresize function...
    if ( Stage.width < minWidth ) {
    	mclogo._x = fixPoint;
    } else {
    	mclogo._x = Stage.width - mclogo._width;
    }
    

    Reply to this comment

  10. Ben 3 years ago

    Hi Soulwire,

    A massive thank you for that, worked a treat, and I learnt something as well : )

    Cheers, Ben

    Reply to this comment

  11. seth 3 years ago

    AS3 implementation

    Soulwire,

    I am looking through your script and trying to implement a centered image (with no scaling) in the header and am having a bugger of a time. I am reading through your explanations above and trying to translate them into AS3. You’ve done a great deal already with this, however, I was hoping you could toss me line.

    Cheers.

    Reply to this comment

  12. Soulwire 3 years ago

    Hey Seth,

    It sounds like your problem comes from putting the image inside the header clip, as the header itself is being stretched and so its children inherit the transformation. Instead, you could try putting your image, or the holder DisplayObject containing it, at the root level of your movie and then target it separately in the onResize script. For a centered element, the logic would be; set it’s x position to 50% of the stage and then minus half of its width.

    Is this roughly what you meant?

    Reply to this comment